網(wǎng)上搜的Spring 生命周期,大部分都是寫個demo,然后說按順序輸出就完事了
但是并沒看到文章提起其位置,估計是這個問題太淺顯了
我debug了一下 Spring 核心的onRefresh方法,結(jié)合以前的一些猜測,大致確認(rèn)ConfigurableListableBeanFactory#createBean是Bean創(chuàng)建的入口
具體的生命周期的流轉(zhuǎn)如下圖所示

其實(shí)大家也可以參照網(wǎng)上的那些文章,直接打斷點(diǎn)看堆棧,就可以得到具體的執(zhí)行位置
Spring中的循環(huán)依賴
循環(huán)依賴其實(shí)就是循環(huán)引用,也就是兩個或者兩個以上的bean互相持有對方,最終形成閉環(huán)。比如A依賴于B,B依賴于C,C又依賴于A。
在這里先解釋一下,Spring中用了三層緩寸來處理循環(huán)依賴
- 1級 singletonFactories : 單例對象的cache
- 2級 earlySingletonObjects :提前暴露的單例對象的Cache
- 3級 singletonFactories : 單例對象工廠的cache
Spring會根據(jù)1->3的順序進(jìn)行Bean的獲取
在上圖的 populateBean方法前,其實(shí)有如下一段代碼判斷是否存在循環(huán)依賴
// 若 RootBeanDefinition 是 單例 且 允許容器嘗試解決循環(huán)依賴問題
// 且 singletonsCurrentlyInCreation的map中包含當(dāng)前的BeanName
boolean earlySingletonExposure = mbd.isSingleton()
&& this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
// 如果需要提前暴露
if (earlySingletonExposure) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Eagerly caching bean '" + beanName
+ "' to allow for resolving potential circular references");
}
// 將其加入第三級緩存
this.addSingletonFactory(beanName, () -> {
return this.getEarlyBeanReference(beanName, mbd, bean);
});
}
Object exposedObject = bean;
讓我們來分析一下“A的某個field或者setter依賴了B的實(shí)例對象,同時B的某個field或者setter依賴了A的實(shí)例對象”這種循環(huán)依賴的情況。A首先完成了初始化的第一步,并且將自己提前曝光到singletonFactories中,此時進(jìn)行初始化的第二步,發(fā)現(xiàn)自己依賴對象B,此時就嘗試去get(B),發(fā)現(xiàn)B還沒有被create,所以走create流程,B在初始化第一步的時候發(fā)現(xiàn)自己依賴了對象A,于是嘗試get(A),嘗試一級緩存singletonObjects(肯定沒有,因?yàn)锳還沒初始化完全),嘗試二級緩存earlySingletonObjects(也沒有),嘗試三級緩存singletonFactories,由于A通過ObjectFactory將自己提前曝光了,所以B能夠通過ObjectFactory.getObject拿到A對象(雖然A還沒有初始化完全,但是總比沒有好呀),B拿到A對象后順利完成了初始化階段1、2、3,完全初始化之后將自己放入到一級緩存singletonObjects中。此時返回A中,A此時能拿到B的對象順利完成自己的初始化階段2、3,最終A也完成了初始化,進(jìn)去了一級緩存singletonObjects中,而且更加幸運(yùn)的是,由于B拿到了A的對象引用,所以B現(xiàn)在hold住的A對象完成了初始化?!?a target="_blank">來源博客
后續(xù)還有一次循環(huán)依賴檢查,檢查提前暴露的對象是否被動態(tài)代理等修改為新的對象,如果有則報錯
這里有篇文章可以參考
傳送門