Spring IOC容器啟動流程原始碼解析(四)——初始化單例項bean階段
目錄
1. 引言
之前開了一個解讀IOC容器啟動原始碼的坑Spring IOC容器啟動流程原始碼解析(一)——容器概念詳解及原始碼初探,不過由於最近比較忙,這個坑挖了卻一直沒時間填。最近在看分散式事務相關的開源專案,碰到了一些Spring AOP相關的問題,比如Spring AOP中的增強邏輯是何時以何種方式織入目標類中的;多個切面的執行順序如何確定;如何以反射的方式呼叫事務方法等等,才發現我對Spring AOP的底層瞭解的還是太少了。Spring AOP預設使用動態代理的方式在執行時織入切面,這個動態代理物件需要由Spring容器建立並進行管理。因而,深入瞭解Spring AOP的前提就是熟悉IOC容器建立一個例項的過程,這個過程清晰了,自然也就找到了繼續深入研究Spring AOP的入口。趁著這個機會就先來好好梳理下IOC容器建立例項的流程,順便也把解讀IOC容器啟動原始碼這個大坑的第四部分(初始化單例項bean)先填了,其實這也是整個IOC容器啟動流程中最重要的階段,這部分內容非常複雜,細節相當多,對這部分的講解主要還是以梳理流程為主,知道容器初始化單例項bean的過程分為哪幾個階段,每個階段主要做了哪些工作,解決了哪些重要的問題,一些和容器核心功能無關的細節可以適當忽略,這樣分清主次更有助於理解。
2. 初始化bean的入口
整個IOC容器的啟動過程都包含在容器抽象類AbstractApplicationContext
的模板方法refresh()
中
在這之前已經建立了核心容器BeanFactory,完成了bean定義資訊的載入解析和註冊,對於使用者定義的每一個bean,建立一個對應的BeanDefinition,以beanName為key,Definition為value儲存在核心容器beanFactory的map中。
這個時候還沒有真正建立Bean,而是建立了一個Bean的設計圖——BeanDefinition,之後可以根據這個BeanDefinition建立真正的Bean例項。完成核心容器的建立後,還會註冊一些容器的基礎元件,之後才會來到啟動容器最重要的階段——初始化bean的階段,這部分的入口在finishBeanFactoryInitialization(beanFactory)
進入finishBeanFactoryInitialization(beanFactory)方法,在真正進行初始化動作前還會有一些準備工作,這部分內容因為不是特別重要,就在這順便提及下
上面這部分邏輯中,容器提前初始化了兩類特殊的bean,一類是ConversionService,可以進行屬性值的轉化,比如將前端傳過來的特定格式的時間字串轉化為Date物件,功能和PropertyEditor類似;另一類則是實現了LoadTimeWeaverAware介面的Bean,這部分和Spring中的LTW(LoadTimeWeaving)相關,儘管也是AOP,但並不是Spring AOP中的預設實現。初始化時通過呼叫BeanFactory的getBean(..)方法實現的,這個方法其實才是初始化bean的真正入口,不過後面還會碰到,這裡就跳過。進入箭頭所指的方法,從方法名可以得知,下面這部分還是屬於準備階段的次要內容
//獲取所有BeanDefinition的beanName
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
//遍歷所有beanName
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//如果bean不是抽象的且單例且非懶載入則通過if條件
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
//如果是實現FactoryBean介面的bean
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
//初始化bean的真正入口
getBean(beanName);
}
}
}
else {
//不是FactoryBean則執行這裡,這是初始化bean的真正入口
getBean(beanName);
}
}
}
這裡會拿到之前註冊的所有BeanDefinition,進行初始化的條件判斷,如果Bean被設定為單例(scope=singleton)且非懶載入(lazy-init=false)則會開始真正的初始化流程,如果這其中任一條件不滿足,則在容器啟動的過程中是不會初始化這個bean的。之後的處理邏輯根據bean是否為FactoryBean型別而有所不同,但最後多會呼叫getBean()方法,這個方法其實才是初始化bean的真正的入口方法。
3 嘗試從當前容器及其父容器的快取中獲取bean
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
這其實是一個相當通用的方法,它的真正含義其實是供客戶端從容器中獲取bean,若客戶端想要的bean不存在,容器當然會建立並初始化它,但bean可能已經建立好並快取在容器中,那麼直接把快取的物件返回給客戶端就好,所以這個方法的字首是get而不是create。不過我們是在IOC容器的啟動流程中去分析這個方法,這個上下文環境下,所有bean都還未建立,所以這就相當於一個初始化方法。進入內部的doGetBean()方法,這個方法比較長,但是流程還是比較清晰的。
3.1 獲取真正的beanName
這是transformedBeanName(name)做的工作
//對原始的beanName進行轉化,獲取真實的beanName,如果是FactoryBean則去除字首'&',如果是別名則通過
//別名獲取真實的名稱
final String beanName = transformedBeanName(name);
Object bean;
3.2 嘗試從當前容器的快取中獲取bean
// 從快取中獲取bean若快取中不存在則從其ObjectFactory中獲取,若ObjectFactory不存在則返回null
Object sharedInstance = getSingleton(beanName);
這個getSingleton(beanName)比較值得講,一是因為後面還會見到,二是它和spring解決bean迴圈依賴的方式有關,因而有必要理解其實現原理。
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//先嚐試從singletonObjects這個快取map中獲取,這是個全域性的快取,裡面存放著真正建立完成的bean
//單例的bean只會被建立一次,之後便會快取在這個map中供客戶端重複獲取
Object singletonObject = this.singletonObjects.get(beanName);
//如果快取中不存在該name的bean且該bean正在建立過程中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//同步
synchronized (this.singletonObjects) {
//嘗試從earlySingletonObjects這個快取map中獲取bean,這個map中的bean並未真正建立完成
//但是提前暴露出來用來解決依賴問題
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//若依舊未獲取到則從singletonFactories這個map中獲取其工廠
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//成功獲取該bean的工廠例項
//呼叫工廠方法獲取bean
singletonObject = singletonFactory.getObject();
//將該bean加入earlySingletonObjects這個map中
this.earlySingletonObjects.put(beanName, singletonObject);
//將建立該bean的工廠從singletonFactories中移除
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
從快取中獲取bean的流程並不複雜,但是因為涉及到3個Map,所以邏輯有點繞。
- 全域性快取singletonObjects
/**
* Cache of singleton objects: bean name to bean instance.
*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
這個map用來快取真正建立完成的bean,真正建立完成是指物件存在且所有屬性/依賴已經注入且所有初始化操作已經完成。
- 提前暴露bean的快取earlySingletonObjects
/**
* Cache of early singleton objects: bean name to bean instance.
*/
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
這個map中的bean併為真正建立完成,但是提前放在這個map中暴露出來,主要是為了解決迴圈依賴問題。
- bean工廠快取singletonFactories
/**
* Cache of singleton factories: bean name to ObjectFactory.
*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
這個map中快取的是用來獲取bean的工廠ObjectFactopry,這個工廠中有一個剛建立完成但是未注入屬性也未進行初始化的bean,當從工廠中取出這個bean後,該bean會快取到earlySingletonObjects這個map中,並且對應的工廠會從singletonFactories移除。
為什麼要搞的這麼複雜?這和Spring解決bean之間的迴圈依賴的思路有關:Spring在建立Bean A時如果發現A依賴於B會先去建立B,這個發現的時機其實是在為A注入屬性時,此時bean A其實已經被建立,但是還未進行任何屬性賦值和初始化操作,此時會將這個原始的bean A封裝在一個ObjectFactory工廠中,儲存在singletonFactories快取,之後在建立B的過程中如果又需要建立A則會從快取中獲取A的工廠,呼叫其getObject()方法獲取其實力,並將例項物件A放入earlySingletonObjects這個快取中,之後將對應的ObjectFactory從singletonFactories中移除。
因而getSingleton()
的邏輯就是根據beanName先從全域性快取中查詢bean,沒找到再從工廠快取查詢其工廠,找到就從工廠中取出,沒找到上的話則返回null。
// 從快取中獲取bean若快取中不存在則從其ObjectFactory中獲取,若ObjectFactory不存在則返回null
Object sharedInstance = getSingleton(beanName);
3.3 從父容器中查詢bean
這裡我們假設之前沒有從當前容器的快取中找到bean,這樣比較符合初始化語境。這時候sharedInstance為null,接著會嘗試從當前容器的父容器中去獲取
// Check if bean definition exists in this factory.
//獲取父容器,嘗試從父容器中獲取
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
//遞迴從父容器中獲取想要的bean
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
邏輯可以簡化為:獲取當前容器的父容器並遞迴呼叫getBean()方法進行查詢
3.4 解析bean的依賴
這裡有解析bean依賴的操作,原來我一直以為這裡就是遞迴建立依賴bean的入口,但其實這裡正如註釋所言,只是為了保證當前bean的所有依賴bean已經初始化完畢,
真正開始解析bean之間的依賴關係其實是在後面為bean注入屬性時,當發現bean A依賴於bean B時,會暫停A的屬性注入和初始化操作轉而去建立B。所以這部分不是很重要,瞭解下即可。
// Guarantee initialization of beans that the current bean depends on.
//保證該bean所有依賴的bean已經初始化完畢
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 + "'");
}
//記錄與當前bean有關的依賴關係
registerDependentBean(dep, beanName);
try {
//先嚐試獲取該bean所依賴的bean
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
3.5 再一次嘗試從快取中獲取
這裡再一次呼叫了getSingleton()方法,不過這次傳遞了一個實現ObjectFactory介面的匿名內部類(lambda語法簡化),
@FunctionalInterface
public interface ObjectFactory<T> {
/**
* Return an instance (possibly shared or independent)
* of the object managed by this factory.
* @return the resulting instance
* @throws BeansException in case of creation errors
*/
T getObject() throws BeansException;
}
// Create bean instance.
if (mbd.isSingleton()) {
//走到這裡說明bean的定義是單例項的
//嘗試從全域性快取中獲取bean,若沒獲取到則通過BeanDefinition資訊建立bean,並清理相關快取
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
//從FactoryBean中獲取真正的bean例項
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
首先還是會嘗試從全域性快取中獲取bean,如果不存在才會呼叫工廠的getObject()方法去建立該bean,這個匿名內部類的getObject()方法又呼叫了createBean()方法,這個方法定義在AbstractBeanFactory
這個抽象工廠類中,不過具體實現在其子類AbstractAutowireCapableBeanFactory
,這個類中的createBean()才是真正建立Bean的方法
4. 真正建立Bean的方法createBean()
兜兜轉轉終於來到了最重要的真正建立bean的方法,來到這個方法,說明從快取中獲取bean的嘗試失敗,轉為真正建立並初始化它。
4.1 例項化bean的前置處理
- 解析class
//根據設定的class屬性或者根據className來解析Class
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
- 對override屬性進行標記及驗證
// Prepare method overrides.
try {
//2.對override屬性進行標記及驗證
mbdToUse.prepareMethodOverrides();
}
這裡和Spring的方法注入功能相關,Spring除了有構造器注入、屬性注入和工廠方法注入外還有方法注入
spring的bean配置中存在lookup-method和replace-method兩個配置,這兩個放在BeanDefinition的methodOverrides屬性中
如果bean例項化的時候檢測到methodOverrides屬性,會動態的為當前bean生成動態代理並使用相關攔截器對bean做增強,
其底層通過CGLib在執行期動態操作Class位元組碼實現
比如bean定義中的
方便為單例項bean的多例項屬性注入依賴且與Spring容器沒有耦合;還有一種
的方法替換另一個bean的方法。
- 例項化前的後置處理器回撥
這裡應該是初始化bean的流程中第一個允許使用者進行回撥的擴充套件點。
在講解這部分原始碼前先了解下一個特殊的後置處理器——InstantiationAwareBeanPostProcessor
它擴充套件自BeanPostProcessor
它內部定義了三個回撥方法,其中比較重要的是下面這個
@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
在物件例項化前回調,可以通過回撥該方法返回一個代理物件來替代預設的物件例項化過程
好了可以開始講這部分的原始碼了
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
//例項化bean之前的處理,會獲取所有的InstantiationAwareBeanPostProcessor,執行其回撥方法
//這部分和Spring AOP相關
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
//短路控制,例項化bean之前的前置處理過程返回的bean如果不為空,則直接返回該bean
if (bean != null) {
return bean;
}
}
/**
* Apply before-instantiation post-processors, resolving whether there is a
* before-instantiation shortcut for the specified bean.
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @return the shortcut-determined bean instance, or {@code null} if none
*/
@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
//尚未被解析
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
// 執行例項化前置方法
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
//執行例項化後置方法
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
@Nullable
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}
獲取後處理器並回調的邏輯封裝在resolveBeforeInstantiation()方法中,注意這裡的返回值,如果返回值不為null,直接return,不走後面的例項化流程了。
值得一提的是,通過Spring在這裡提供的擴充套件點,確實有可能返回一個代理物件,那麼Spring AOP生成的動態代理物件是這裡生成的嗎?很遺憾,通常情況並不是,除非你做了相關的自定義設定。
當resolveBeforeInstantiation)()方法返回的結果為null,會執行後續的常規例項化操作。
try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
doCreateBean是例項化bean的核心方法
4.2 選擇合適的策略建立bean例項
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//例項化bean,這裡根據BeanDefinition建立BeanWrapper
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
createBeanInstance()裡面是建立bean例項(準確來說是個bean的wrapper物件)的過程,這個過程設計兩類策略的選擇
-
- 選擇合適的構造器
這部分內容比較長,就不貼原始碼了,核心思想是:如果設定了factory-method屬性,則使用工廠方法建立例項,否則根據引數的個數和型別選擇構造器進行例項化,這裡因為解析構造器比較花時間所以做了
快取處理,使得整個邏輯變得更加複雜。
- 選擇合適的構造器
- 2.選擇例項化策略例項化物件
選擇了合適的構造器後,容器會根據bean的定義中是否存在需要動態改變的方法(lookup-method,replace-method)選擇不同的例項化策略:不存在則直接使用反射建立物件;存在則使用cglib生成子類的方式動態的
進行方法替換。
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
final Constructor<?> ctor, Object... args) {
//判斷是否有需要動態改變(lookup-method動態重寫,replace-method動態替換)的方法
if (!bd.hasMethodOverrides()) {
if (System.getSecurityManager() != null) {
// use own privileged to change accessibility (when security is on)
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
ReflectionUtils.makeAccessible(ctor);
return null;
});
}
//不存在需要動態改變的方法,直接使用反射建立物件
return BeanUtils.instantiateClass(ctor, args);
}
else {
//存在需要動態改變的方法,使用cglib生成子類的方式動態替換原有方法
return instantiateWithMethodInjection(bd, beanName, owner, ctor, args);
}
}
4.3 填充bean的屬性,解析依賴,遞迴建立依賴的bean
之前只是建立了一個空的bean,為bean的屬性進行賦值通過下面的方法完成
populateBean(beanName, mbd, instanceWrapper);
整個過程可以分為4步:
- 1.獲取所有的InstantiationAwareBeanPostProcessor,執行其postProcessAfterInstantiation方法,只要其中一個處理器返回false,將終止屬性填充直接返回,這部分程式碼在下面
//呼叫InstantiationAwareBeanPostProcessor的例項化後置處理方法
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
//其中一個處理器的回撥方法返回false,則跳出迴圈
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (!continueWithPropertyPopulation) {
//不執行後續的屬性填充操作,直接返回
return;
}
- 2.根據注入型別,遞迴初始化依賴的bean
//根據名稱或者型別進行依賴注入
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
//按名稱進行依賴注入
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
//按型別進行依賴注入
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
這裡嘗試為bean注入依賴,可以按名稱或者按型別進行注入。這裡才是真正開始進行依賴解析並遞迴建立bean的地方,以autowireByName()為入口一探究竟
1處開始遞迴建立依賴的bean
2處則是講與當前bean有關的依賴關係進行註冊,主要是填充兩個map
public void registerDependentBean(String beanName, String dependentBeanName) {
String canonicalName = canonicalName(beanName);
//dependentBeanMap<String(beanName),Set<String>(依賴於前者的所有beanName集合)>
synchronized (this.dependentBeanMap) {
Set<String> dependentBeans =
this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
if (!dependentBeans.add(dependentBeanName)) {
//已經存在
return;
}
}
//dependenciesForBeanMap<String(beanName), Set<String>(被前者依賴的所有beanName集合)>
synchronized (this.dependenciesForBeanMap) {
Set<String> dependenciesForBean =
this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
dependenciesForBean.add(canonicalName);
}
}
dependentBeanMap:value為依賴於當前bean的所有bean的beanName集合
dependenciesForBeanMap:value為當前bean所依賴的所有bean的beanName集合
- 3.將所有待填充的屬性儲存在PropertyValues中,進一步處理
主要是獲取所有的InstantiationAwareBeanPostProcessor並回調其postProcessPropertyValues方法
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
- 4.執行屬性填充
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
這步執行完畢,bean的所有依賴就都已經注入,所有屬性都已經填充完畢了
4.4 初始化bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
- 1.如果bean實現了相關Aware介面:BeanNameAware,BeanClassLoaderAware,BeanFactoryAware,則回撥其相應的set方法
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
- 2.回撥BeanPostProcessor的初始化前置方法
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
//回撥其初始化前置方法
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
- 3.執行初始化方法
這裡的初始化方法有兩種,一種是使用者在定義bean時配置的init-method,一種是InitialLizingBean介面的的afterProperties()方法
- 4.回撥BeanPostProcessor的初始化後置方法
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
//回撥初始化後置方法
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
到這裡基本上IOC容器建立bean的流程就結束了,只有還有一些無關緊要的內容,就不貼原始碼了。
5. 總結
本來還希望容器初始化單例項bean這部分內容能夠講的簡單清晰,主次分明些,想不到還是寫成了流水賬,唯一值得欣慰的地方大概是終於把容器啟動流程中最複雜也是最重要的階段——初始化單例項bean的過程好好梳理了一遍,想繼續探討AOP原始碼的話也能找到切入點了。最後以下面這張圖作為總結吧,基本理清了容器例項化bean的過程以及解決迴圈依賴的思路。
假設要建立的bean A和B之間存在迴圈依賴,整個過程如下圖所示
6. 參考資料
《spring原始碼深度解析》