一圖看懂 Spring Bean 生命周期 原理

網(wǎng)上搜的Spring 生命周期,大部分都是寫個demo,然后說按順序輸出就完事了
但是并沒看到文章提起其位置,估計是這個問題太淺顯了

我debug了一下 Spring 核心的onRefresh方法,結(jié)合以前的一些猜測,大致確認(rèn)ConfigurableListableBeanFactory#createBean是Bean創(chuàng)建的入口

具體的生命周期的流轉(zhuǎn)如下圖所示

Spring Bean生命周期 單例.png

其實(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)代理等修改為新的對象,如果有則報錯
這里有篇文章可以參考
傳送門

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容