讀完這篇文章你將會收穫到
Spring
何時將bean
加入到第三級緩存和第一級緩存中Spring
何時回調各種Aware
接口、BeanPostProcessor
、InitializingBean
等
相關文章
- Spring 獲取單例流程(一)
- Spring 獲取單例流程(二)
- Spring 循環依賴 (公衆號內查看(同時發佈無法獲取到鏈接))
概述
上兩篇文章 Spring 獲取單例流程(一) 和 Spring 獲取單例流程(二) 介紹了 getBean
前面的流程,今天最後的收尾,把後面的流程繼續一起學習下
源碼分析
// 我依賴的大哥都好了
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
} catch (BeansException ex) {
// 從三級緩存中移除這個 beanName 因爲它可能被放進去了 因爲放進去三級緩存可以解決 setter 的循環依賴
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
如果我們要創建的 bean
是一個單例,
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
// 看看第一級緩存中有沒有
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 將 beanName 加入到 singletonsCurrentlyInCreation 中,代表它正在創建中
beforeSingletonCreation(beanName);
boolean newSingleton = false;
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
} catch (IllegalStateException ex) {
throw ex;
} catch (BeanCreationException ex) {
throw ex;
} finally {
// singletonsCurrentlyInCreation 從這裏面移除掉
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 加入緩存中
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
刪減了部分不重要的代碼,我們大致來看看其流程
- 獲取同步鎖,然後判斷第一級緩存是否已經存在這個
bean
了 - 如果不存在則將
beanName
加入到singletonsCurrentlyInCreation
中,代表它正在創建中 - 然後調用參數的
ObjectFactory
的getObject
方法獲得一個bean
- 最後將其從
singletonsCurrentlyInCreation
中移除、代表其已經創建完成了 - 最後將其加入到第一級緩存中、從第二級和第三級緩存中移除掉
全篇完結.終 !!!
其實真正的祕密藏身在參數的 ObjectFactory
中,從上面的流程中可以宏觀的知道 Spring
創建 bean
的一個流程
現在我們在看看參數的 ObjectFactory
究竟幹啥子了
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
...........
...........
try {
// 真正 處理邏輯
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
} catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(xxxx);
}
}
幹活的還是 do
開頭的大佬
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 根據指定 bean 使用對應的策略創建新的實例、如工廠方法、構造函數自動注入、簡單初始化
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
..........
.........
// 是否需要提前曝光、用來解決循環依賴的問題
// 是單例&允許循環依賴&正在創建中
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// 爲了避免後期循環依賴、可以在 bean 初始化前將創建實例的ObjectFactory 加入工廠
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 填充屬性
populateBean(beanName, mbd, instanceWrapper);
// 調用初始方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
} catch (Throwable ex) {
.........
}
........
.......
return exposedObject;
}
上面的流程大致就是
-
createBeanInstance
這個方法根據你的配置以及你的bean
的情況選擇出一種創建bean
的方法、可能是工廠方法、可能是某個構造函數、可能是默認的構造函數。這裏包含了當一個構造函數的參數是另一個bean
的時候、它會通過getBean
的方法獲取這個參數的bean
-
然後將創建好的
bean
加入到第三級緩存中,默認設置我們是允許循環依賴的 -
populateBean
方法就是我們填充屬性了、如果你依賴的其他Spring
的其他bean
是通過這種方式注入的話(autowireByName``````autowireByType
)、就是在這一步注入的了,他獲取其他bean
也是通過getBean
的方式獲取protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { ......... ......... if (resolvedAutowireMode == AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } // Add property values based on autowire by type if applicable. if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) { autowireByType(beanName, mbd, bw, newPvs); } ......... ......... }
-
initializeBean
則是調用我們的各種回調接口、Aware
類型的、BeanPostProcessor
、InitializingBean
、自定義初始化函數protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> {。 // 調用各種 Aware 接口 invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { // 調用各種 Aware 接口 invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { // 調用 BeanPostProcessor postProcessBeforeInitialization wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { // 調用 InitializingBean 、自定義的初始化方法 invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { // 調用 BeanPostProcessor postProcessAfterInitialization wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
其實整體的流程就差不多了
總結
- 根據參數中的
name
找出對應的beanName
、無論這個name
是別名或者是一個factoryBean
的beanName
- 查看緩存中是否包含這個
beanName
對象- 先從一級緩存
singletonObjects
中看看有沒有 - 然後從二級緩存
earlySingletonObjects
- 都沒有的話再從三級緩存
singletonFactories
中看看有沒有
- 先從一級緩存
- 如果緩存中有
bean
、那麼我們還是需要處理一下這個bean
- 如果
Spring
緩存中返回的bean
是factoryBean
、而用戶也想要的是一個beanFactory
(參數name
中的前綴是&
)、那麼我們直接返回 - 如果
Spring
緩存中返回的bean
是普通的bean
、而用戶也想要的是一個普通的bean
、那麼就直接返回 - 如果
Spring
緩存中返回的bean
是一個factoryBean
、而用戶想要的是一個普通的bean
、那麼我們就要從factoryBean
中獲取這個bean
- 而從
factoryBean
中獲取這個bean
的過程中、需要調用到前置處理、後置處理和我們常用的接口回調BeanPostProcessor
- 如果
- 如果緩存中沒有
bean
、則判斷是否是prototype
類型並且循環依賴 - 如果沒有則嘗試能否在父容器中找到該
bean
- 如果父容器也沒有則獲取該
beanName
對應的beanDefinition
找出其依賴的beanName
- 判斷該
beanName
與 依賴的beanName
是否循環依賴、沒有則註冊其依賴關係並調用getBean
方法去創建依賴的beanName
- 將
beanName
加入到singletonsCurrentlyInCreation
中 - 根據指定 bean 使用對應的策略創建新的實例、如工廠方法、構造函數、創建一個不完整的 bean
- 將創建好的 bean 加入到第三級緩存中
- 進行屬性填充、進行各種接口回調
- 最後將其從
singletonsCurrentlyInCreation
中移除、代表其已經創建完成了 - 最後將其加入到第一級緩存中、從第二級和第三級緩存中移除掉
- 返回
bean
給調用方
其實總體的流程還是不算複雜把、我們也可以從中收穫到一些東西。其實我們最關心也是面試最常問的一個問題就是、Spring 如何解決循環依賴的問題、感興趣的可以看看這篇文章公衆號內的 Spring 循環依賴
這篇文章