細化容器啓動流程,加入擴展點:
- 配置是否允許Bean覆蓋、循環依賴:默認屬性 allowBeanDefinitionOverriding 、 allowCircularReferences 都爲 null
- ConversionService 接口:將前端傳過來的參數和後端的 controller 方法上的參數進行綁定的時候用
- Bean 繼承:合併父 Bean 中的配置,注意 <bean id="" class="" parent="" /> 中的 parent
- FactoryBean 接口:適用於 Bean 的創建過程比較複雜的場景,比如數據庫連接池的創建
- lookup-method/@Lookup:指定方法注入
- replaced-method:方法注入覆寫
---------------------------------------------------------
項目啓動通過 ApplicationContext context = new ClassPathXmlApplicationContext(...)
在ClassPath中尋找配置文件,根據配置文件內容來構建ApplicationContext。
除了使用ClassPathXmlApplicationContext之外,可以有還尤其構建 ApplicationContext 的方案可供選擇,下面爲了理解整個構建過程,還是使用ClassPathXmlApplicationContext進行分析。 容器啓動的核心方法是 AbstractApplicationContext 中的refresh()。
其實ApplicationContext就是一個BeanFactory,BeanFactory是Spring裏面最底層的接口,提供了最簡單的容器功能,在bean生命週期的各個階段對bean進行各種管理與接口暴露。下面看一下相關的主要繼承結構:
// 初始化一個 DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
ApplicationContext 繼承自 BeanFactory,但不應該被理解爲 BeanFactory 的實現類,而是說內部持有一個實例化的 BeanFactory (DefaultListableBeanFactory)。那麼爲什麼選擇實例化 DefaultListableBeanFactory?關注一下實現了 BeanFactory 下面一層的所有三個接口的ConfigurableListableBeanFactory 類:
ConfigurableListableBeanFactory 只有一個實現類 DefaultListableBeanFactory,而且實現類 DefaultListableBeanFactory 還通過實現右邊的 AbstractAutowireCapableBeanFactory 通吃了右路。所以結論就是,最底下這個傢伙 DefaultListableBeanFactory 基本上是最牛的 BeanFactory 了,這也是爲什麼這邊會使用這個類來實例化的原因。
下面看一下DefaultListableBeanFactory beanFactory = createBeanFactory()時,DefaultListableBeanFactory存儲了什麼?
/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
/** List of bean definition names, in registration order. */
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
//手動註冊的 singleton bean
private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(...);
}
}
// old? 還記得 “允許 bean 覆蓋” 這個配置嗎?allowBeanDefinitionOverriding
BeanDefinition oldBeanDefinition;
// 之後會看到,所有的 Bean 註冊後會放入這個 beanDefinitionMap 中
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
// 處理重複名稱的 Bean 定義的情況
if (oldBeanDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
// 如果不允許覆蓋的話,拋異常
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription()...
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// log...用框架定義的 Bean 覆蓋用戶自定義的 Bean
}
else if (!beanDefinition.equals(oldBeanDefinition)) {
// log...用新的 Bean 覆蓋舊的 Bean
}
else {
// log...用同等的 Bean 覆蓋舊的 Bean,這裏指的是 equals 方法返回 true 的 Bean
}
// 覆蓋
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
// 判斷是否已經有其他的 Bean 開始初始化了.
// 注意,"註冊Bean" 這個動作結束,Bean 依然還沒有初始化,我們後面會有大篇幅說初始化過程,
// 在 Spring 容器啓動的最後,會 預初始化 所有的 singleton beans
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// 最正常的應該是進到這裏。
// 將 BeanDefinition 放到這個 map 中,這個 map 保存了所有的 BeanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
// 這是個 ArrayList,所以會按照 bean 配置的順序保存每一個註冊的 Bean 的名字
this.beanDefinitionNames.add(beanName);
// 這是個 LinkedHashSet,代表的是手動註冊的 singleton bean,
// 注意這裏是 remove 方法,到這裏的 Bean 當然不是手動註冊的
// 手動指的是通過調用以下方法註冊的 bean :
// registerSingleton(String beanName, Object singletonObject)
// 這不是重點,解釋只是爲了不讓大家疑惑。Spring 會在後面"手動"註冊一些 Bean,如 "environment"、"systemProperties" 等 bean
this.manualSingletonNames.remove(beanName);
}
// 這個不重要,在預初始化的時候會用到,不必管它。
this.frozenBeanDefinitionNames = null;
}
if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
擴展 配置是否允許Bean覆蓋、循環依賴:
默認情況下,allowBeanDefinitionOverriding 屬性爲 null。如果在同一配置文件中 Bean id 或 name 重複了,會拋錯,但是如果不是同一配置文件中,會發生覆蓋。可是有些時候我們希望在系統啓動的過程中就嚴格杜絕發生 Bean 覆蓋,因爲萬一出現這種情況,會增加我們排查問題的成本。
循環依賴說的是 A 依賴 B,而 B 又依賴 A。或者是 A 依賴 B,B 依賴 C,而 C 卻依賴 A。默認 allowCircularReferences 也是 null。
它們兩個屬性是一起出現的,必然可以在同一個地方一起進行配置。
public class NoBeanOverridingContextLoader extends ContextLoader { @Override protected void customizeContext(ServletContext servletContext, ConfigurableWebApplicationContext applicationContext) { super.customizeContext(servletContext, applicationContext); AbstractRefreshableApplicationContext arac = (AbstractRefreshableApplicationContext) applicationContext; arac.setAllowBeanDefinitionOverriding(false); } }
public class MyContextLoaderListener extends org.springframework.web.context.ContextLoaderListener { @Override protected ContextLoader createContextLoader() { return new NoBeanOverridingContextLoader(); } }
<listener> <listener-class>com.javadoop.MyContextLoaderListener</listener-class> </listener>
DefaultListableBeanFactory beanFactory = createBeanFactory()後,下一步 prepareBeanFactory(factory) ,對beanFactory內屬性進行設置。
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 設置 BeanFactory 的類加載器,我們知道 BeanFactory 需要加載類,也就需要類加載器,
// 這裏設置爲當前 ApplicationContext 的類加載器
beanFactory.setBeanClassLoader(getClassLoader());
// 設置 BeanExpressionResolver
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
//
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 添加一個 BeanPostProcessor,這個 processor 比較簡單,
// 實現了 Aware 接口的幾個特殊的 beans 在初始化的時候,這個 processor 負責回調
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 下面幾行的意思就是,如果某個 bean 依賴於以下幾個接口的實現類,在自動裝配的時候忽略它們,
// Spring 會通過其他方式來處理這些依賴。
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
/**
* 下面幾行就是爲特殊的幾個 bean 賦值,如果有 bean 依賴了以下幾個,會注入這邊相應的值,
* 之前我們說過,"當前 ApplicationContext 持有一個 BeanFactory",這裏解釋了第一行
* ApplicationContext 繼承了 ResourceLoader、ApplicationEventPublisher、MessageSource
* 所以對於這幾個,可以賦值爲 this,注意 this 是一個 ApplicationContext
* 那這裏怎麼沒看到爲 MessageSource 賦值呢?那是因爲 MessageSource 被註冊成爲了一個普通的 bean
*/
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// 這個 BeanPostProcessor 也很簡單,在 bean 實例化後,如果是 ApplicationListener 的子類,
// 那麼將其添加到 listener 列表中,可以理解成:註冊事件監聽器
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found.
// 這裏涉及到特殊的 bean,名爲:loadTimeWeaver,這不是我們的重點,忽略它
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
/**
* 從下面幾行代碼我們可以知道,Spring 往往很 "智能" 就是因爲它會幫我們默認註冊一些有用的 bean,
* 我們也可以選擇覆蓋
*/
// 如果沒有定義 "environment" 這個 bean,那麼 Spring 會 "手動" 註冊一個
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
// 如果沒有定義 "systemProperties" 這個 bean,那麼 Spring 會 "手動" 註冊一個
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
// 如果沒有定義 "systemEnvironment" 這個 bean,那麼 Spring 會 "手動" 註冊一個
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
截止目前, 應該說 BeanFactory 已經創建完成。接下來 postProcessBeanFactory(beanFactory); 實現了 BeanFactoryPostProcessor 接口的 Bean 的初始化,invokeBeanFactoryPostProcessors(beanFactory); 執行了其中的 postProcessBeanFactory(factory) 方法。registerBeanPostProcessors(beanFactory); 實現了 BeanPostProcessor 接口的 Bean 也都完成了初始化。(postProcessBeanFactory、invokeBeanFactoryPostProcessors、registerBeanPostProcessors三個方法不做細化)
下面就是最重要的 finishBeanFactoryInitialization(beanFactory); 初始化(含實例化)階段了, 初始化其他還沒被初始化的 singleton beans 了,我們知道它們是單例的,如果沒有設置懶加載,那麼 Spring 會在接下來初始化所有的 singleton beans
// 初始化剩餘的 singleton beans
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 首先,初始化名字爲 conversionService 的 Bean。
// 最有用的場景就是,它用來將前端傳過來的參數和後端的 controller 方法上的參數進行綁定的時候用。
// 像前端傳過來的字符串、整數要轉換爲後端的 String、Integer 很容易,但是如果 controller 方法需要的是一個枚舉值,或者是 Date 這些非基礎類型(含基礎類型包裝類)值的時候,我們就可以考慮採用 ConversionService 來進行轉換。
// 注意了,初始化的動作包裝在 beanFactory.getBean(...) 中,這裏先不說細節,先往下看吧
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
@Override
public String resolveStringValue(String strVal) {
return getEnvironment().resolvePlaceholders(strVal);
}
});
}
// 先初始化 LoadTimeWeaverAware 類型的 Bean
// 一般用於織入第三方模塊,在 class 文件載入 JVM 的時候動態織入,這裏不展開說
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);
// 沒什麼別的目的,因爲到這一步的時候,Spring 已經開始預初始化 singleton beans 了,
// 肯定不希望這個時候還出現 bean 定義解析、加載、註冊。
beanFactory.freezeConfiguration();
// 開始初始化剩下的
beanFactory.preInstantiateSingletons();
}
擴展 ConversionService:
最有用的場景就是,它用來將前端傳過來的參數和後端的 controller 方法上的參數進行綁定的時候用。
像前端傳過來的字符串、整數要轉換爲後端的 String、Integer 很容易,但是如果 controller 方法需要的是一個枚舉值,或者是 Date 這些非基礎類型(含基礎類型包裝類)值的時候,我們就可以考慮採用 ConversionService 來進行轉換。
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <list> <bean class="com.javadoop.learning.utils.StringToEnumConverterFactory"/> </list> </property> </bean>
ConversionService 接口很簡單,所以要自定義一個 convert 的話也很簡單。
下面再說一個實現這種轉換很簡單的方式,那就是實現 Converter 接口。來看一個很簡單的例子,這樣比什麼都管用。
public class StringToDateConverter implements Converter<String, Date> { @Override public Date convert(String source) { try { return DateUtils.parseDate(source, "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "HH:mm:ss", "HH:mm"); } catch (ParseException e) { return null; } } }
只要註冊這個 Bean 就可以了。這樣,前端往後端傳的時間描述字符串就很容易綁定成 Date 類型了,不需要其他任何操作
最後一條語句 beanFactory.preInstantiateSingletons(); 又回到 DefaultListableBeanFactory 這個類了。下面按前文梳理的順序取代碼:
@Override
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Pre-instantiating singletons in " + this);
}
List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
// 觸發所有的非懶加載的 singleton beans 的初始化操作
for (String beanName : beanNames) {
// 合併父 Bean 中的配置,注意 <bean id="" class="" parent="" /> 中的 parent
// 下面進行了擴展補充
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 非抽象、非懶加載的 singletons。如果配置了 'abstract = true',那是不需要初始化的
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 處理 FactoryBean
if (isFactoryBean(beanName)) {
// FactoryBean 的話,在 beanName 前面加上 ‘&’ 符號。再調用 getBean,getBean 方法別急
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
// 判斷當前 FactoryBean 是否是 SmartFactoryBean 的實現,此處忽略,直接跳過
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
return ((SmartFactoryBean<?>) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
else {
// 對於普通的 Bean,只要調用 getBean(beanName) 這個方法就可以進行初始化了
getBean(beanName);
}
}
}
// 到這裏說明所有的非懶加載的 singleton beans 已經完成了初始化
// 如果我們定義的 bean 是實現了 SmartInitializingSingleton 接口的,那麼在這裏得到回調,忽略
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
smartSingleton.afterSingletonsInstantiated();
return null;
}
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
擴展 Bean 繼承:
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); 合併父 Bean 中的配置,注意 <bean id="" class="" parent="" /> 中的 parent
<bean id="inheritedTestBean" abstract="true" class="org.springframework.beans.TestBean"> <property name="name" value="parent"/> <property name="age" value="1"/> </bean> <bean id="inheritsWithDifferentClass" class="org.springframework.beans.DerivedTestBean" parent="inheritedTestBean" init-method="initialize"> <property name="name" value="override"/> </bean>
parent bean 設置了
abstract="true"
所以它不會被實例化,child bean 繼承了 parent bean 的兩個屬性,但是對 name 屬性進行了覆寫。child bean 會繼承 scope、構造器參數值、屬性值、init-method、destroy-method 等等。
當然,不是說 parent bean 中的 abstract = true 在這裏是必須的,只是說如果加上了以後 Spring 在實例化 singleton beans 的時候會忽略這個 bean。
比如下面這個極端 parent bean,它沒有指定 class,所以毫無疑問,這個 bean 的作用就是用來充當模板用的 parent bean,此處就必須加上 abstract = true。
<bean id="inheritedTestBeanWithoutClass" abstract="true"> <property name="name" value="parent"/> <property name="age" value="1"/> </bean>
下面看一下getBean方法,要具備FactoryBean的知識,下面擴展一下。
擴展 FactoryBean:
FactoryBean 適用於 Bean 的創建過程比較複雜的場景,比如數據庫連接池的創建。
public interface FactoryBean<T> { T getObject() throws Exception; Class<T> getObjectType(); boolean isSingleton(); }
public class Person { private Car car ; private void setCar(Car car){ this.car = car; } }
假設現在需要創建一個 Person 的 Bean,首先需要一個 Car 的實例,這裏假設 Car 的實例創建很麻煩,那麼可以把創建 Car 的複雜過程包裝起來:
public class MyCarFactoryBean implements FactoryBean<Car>{ private String make; private int year ; public void setMake(String m){ this.make =m ; } public void setYear(int y){ this.year = y; } public Car getObject(){ // 這裏假設 Car 的實例化過程非常複雜,反正就不是幾行代碼可以寫完的那種 CarBuilder cb = CarBuilder.car(); if(year!=0) cb.setYear(this.year); if(StringUtils.hasText(this.make)) cb.setMake( this.make ); return cb.factory(); } public Class<Car> getObjectType() { return Car.class ; } public boolean isSingleton() { return false; } }
看看裝配的時候是怎麼配置的:
<bean class = "com.javadoop.MyCarFactoryBean" id = "car"> <property name = "make" value ="Honda"/> <property name = "year" value ="1984"/> </bean> <bean class = "com.javadoop.Person" id = "josh"> <property name = "car" ref = "car"/> </bean>
看到不一樣了嗎?id 爲 “car” 的 bean 其實指定的是一個 FactoryBean,不過配置的時候,我們直接讓配置 Person 的 Bean 直接依賴於這個 FactoryBean 就可以了。中間的過程 Spring 已經封裝好了。 現在還用 xml 配置 Bean 依賴的越來越少了,更多時候,我們可能會採用 java config 的方式來配置,這裏有什麼不一樣呢?
@Configuration public class CarConfiguration { @Bean public MyCarFactoryBean carFactoryBean(){ MyCarFactoryBean cfb = new MyCarFactoryBean(); cfb.setMake("Honda"); cfb.setYear(1984); return cfb; } @Bean public Person aPerson(){ Person person = new Person(); // 注意這裏的不同 person.setCar(carFactoryBean().getObject()); return person; } }
這個時候,其實思路也很簡單,把 MyCarFactoryBean 看成是一個簡單的 Bean 就可以了,不必理會什麼 FactoryBean,它是不是 FactoryBean 和我們沒關係。
回過頭,繼續看getBean——>doGetBean。
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
// 我們在剖析初始化 Bean 的過程,但是 getBean 方法我們經常是用來從容器中獲取 Bean 用的,注意切換思路,
// 已經初始化過了就從容器中直接返回,否則就先初始化再返回
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
// 獲取一個 “正統的” beanName,處理兩種情況,一個是前面說的 FactoryBean(前面帶 ‘&’),
// 一個是別名問題,因爲這個方法是 getBean,獲取 Bean 用的,你要是傳一個別名進來,是完全可以的
final String beanName = transformedBeanName(name);
// 注意跟着這個,這個是返回值
Object bean;
// 檢查下是不是已經創建過了
Object sharedInstance = getSingleton(beanName);
// 這裏說下 args 唄,雖然看上去一點不重要。前面我們一路進來的時候都是 getBean(beanName),
// 所以 args 其實是 null 的,但是如果 args 不爲空的時候,那麼意味着調用方不是希望獲取 Bean,而是創建 Bean
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("...");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 下面這個方法:如果是普通 Bean 的話,直接返回 sharedInstance,
// 如果是 FactoryBean 的話,返回它創建的那個實例對象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
if (isPrototypeCurrentlyInCreation(beanName)) {
// 當前線程已經創建過了此 beanName 的 prototype 類型的 bean,那麼拋異常
throw new BeanCurrentlyInCreationException(beanName);
}
// 檢查一下這個 BeanDefinition 在容器中是否存在
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 如果當前容器不存在這個 BeanDefinition,試試父容器中有沒有
String nameToLookup = originalBeanName(name);
if (args != null) {
// 返回父容器的查詢結果
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
// typeCheckOnly 爲 false,將當前 beanName 放入一個 alreadyCreated 的 Set 集合中。
markBeanAsCreated(beanName);
}
/*
* 稍稍總結一下:
* 到這裏的話,要準備創建 Bean 了,對於 singleton 的 Bean 來說,容器中還沒創建過此 Bean;
* 對於 prototype 的 Bean 來說,本來就是要創建一個新的 Bean。
*/
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// 先初始化依賴的所有 Bean,這個很好理解。
// 注意,這裏的依賴指的是 depends-on 中定義的依賴
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
// 檢查是不是有循環依賴,這裏的循環依賴和我們前面說的循環依賴又不一樣,這裏肯定是不允許出現的,不然要亂套了,讀者想一下就知道了
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// 註冊一下依賴關係
registerDependentBean(dep, beanName);
// 先初始化被依賴項
getBean(dep);
}
}
// 創建 singleton 的實例
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
// 執行創建 Bean,詳情後面再說
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 創建 prototype 的實例
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
// 執行創建 Bean
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 如果不是 singleton 和 prototype 的話,需要委託給相應的實現類來處理
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
// 執行創建 Bean
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// 最後,檢查一下類型對不對,不對的話就拋異常,對的話就返回了
if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
下面到了createBean方法
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// 確保 BeanDefinition 中的 Class 被加載
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// 準備方法覆寫,這裏又涉及到一個概念:MethodOverrides,它來自於 bean 定義中的 <lookup-method />
// 和 <replaced-method />,如果讀者感興趣,回到 bean 解析的地方看看對這兩個標籤的解析。
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// 讓 BeanPostProcessor 在這一步有機會返回代理,而不是 bean 實例,
// 要徹底瞭解清楚這個,需要去看 InstantiationAwareBeanPostProcessor 接口,這裏就不展開說了
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
// 重頭戲,創建 bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
擴展 方法注入之lookup-method:
package fiona.apple; // no more Spring imports! public abstract class CommandManager { public Object process(Object commandState) { // grab a new instance of the appropriate Command interface Command command = createCommand(); // set the state on the (hopefully brand new) Command instance command.setState(commandState); return command.execute(); } // okay... but where is the implementation of this method? protected abstract Command createCommand(); }
<!-- a stateful bean deployed as a prototype (non-singleton) --> <bean id="myCommand" class="fiona.apple.AsyncCommand" scope="prototype"> <!-- inject dependencies here as required --> </bean> <!-- commandProcessor uses statefulCommandHelper --> <bean id="commandManager" class="fiona.apple.CommandManager"> <lookup-method name="createCommand" bean="myCommand"/> </bean>
Spring 採用 CGLIB 生成字節碼的方式來生成一個子類。我們定義的類不能定義爲 final class,抽象方法上也不能加 final。
lookup-method 上的配置也可以採用註解來完成,這樣就可以不用配置
<lookup-method />
了,其他不變:public abstract class CommandManager { public Object process(Object commandState) { MyCommand command = createCommand(); command.setState(commandState); return command.execute(); } @Lookup("myCommand")//或 @Lookup protected abstract Command createCommand(); }
上面的返回值用了 MyCommand,當然,如果 Command 只有一個實現類,那返回值也可以寫 Command 。
擴展 方法注入之replaced-method: 就是替換掉 bean 中的一些方法
public class MyValueCalculator { public String computeValue(String input) { // some real code... } // some other methods... }
方法覆寫,注意要實現 MethodReplacer 接口:
public class ReplacementComputeValue implements org.springframework.beans.factory.support.MethodReplacer { public Object reimplement(Object o, Method m, Object[] args) throws Throwable { // get the input value, work with it, and return a computed result String input = (String) args[0]; ... return ...; } }
<bean id="myValueCalculator" class="x.y.z.MyValueCalculator"> <!-- 定義 computeValue 這個方法要被替換掉 --> <replaced-method name="computeValue" replacer="replacementComputeValue"> <arg-type>String</arg-type> </replaced-method> </bean> <bean id="replacementComputeValue" class="a.b.c.ReplacementComputeValue"/>
arg-type 明顯不是必須的,除非存在方法重載,這樣必須通過參數類型列表來判斷這裏要覆蓋哪個方法。
往裏看 doCreateBean 方法:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 說明不是 FactoryBean,這裏實例化 Bean,這裏非常關鍵,細節之後再說
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 這個就是 Bean 裏面的 我們定義的類 的實例,很多地方我描述成 "bean 實例"
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
// 類型
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
mbd.resolvedTargetType = beanType;
// 建議跳過吧,涉及接口:MergedBeanDefinitionPostProcessor
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// MergedBeanDefinitionPostProcessor,這個我真不展開說了,直接跳過吧,很少用的
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// 下面這塊代碼是爲了解決循環依賴的問題,前文有說過,可以結合着看
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 這一步也是非常關鍵的,這一步負責屬性裝配,因爲前面的實例只是實例化了,並沒有設值,這裏就是設值
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
// 還記得 init-method 嗎?還有 InitializingBean 接口?還有 BeanPostProcessor 接口?
// 這裏就是處理 bean 初始化完成後的各種回調
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
//
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
到這裏,我們已經分析完了 doCreateBean 方法,總的來說,我們已經說完了整個初始化流程。
接下來我們挑 doCreateBean 中的三個細節出來說說。一個是創建 Bean 實例的 createBeanInstance 方法,一個是依賴注入的 populateBean 方法,還有就是回調方法 initializeBean。本文到此結束,下一文,繼續挖!