日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Spring是如何解決循環依賴的?

作者:不隨意的風 更新時間: 2022-09-05 編程語言

什么叫循環依賴:簡單來說,在spring中對象的創建管理都是IOC容器幫我們做的,以默認單例的方式幫我們創建bean,但是會出現一個問題:對象A里面有個屬性是B對象,B對象里面又有一個A對象。如下

class A {
    private B b;
}
class B{
     private A a;
}

不管先創建哪個對象,在屬性賦值時都要需要另一個對象。假設創建A對象,需要屬性賦值的時候,發現需要B對象,去創建B對象的時候,發現需要A對象,此時A對象還未創建完,這樣就形成了一個簡單的循環依賴問題。

流程圖:

? ????????此時容器中當然沒有A和B對象,可以發現此時已經形成了一個閉環,也就是循環依賴。解決的關鍵在于:下圖的最后一步沒找到

?此時若能解決此處的問題,閉環將被打破。關鍵點在于此時A對象已經實例化了,但還未完成初始化(半成品對象)。

?????????這時候,請思考一個問題,如果我們持有一個對象的引用(C中的指針),能否在后續的步驟中給這個對象進行賦值操作?

當然是可以的,在這個問題的基礎上,我們可以引入一個東西,來解決循環依賴,就是大家所熟悉的緩存。稍稍加點改動,只需要我們實例化后將對象放入緩存,從容器中查找時,也查找緩存就可以解決循環依賴。此時B已經是成品對象了并且在緩存中,然后A對象就可以完成初始化了。

?當然成品對象和半成品對象放在一起怎么看都不合適,所以spring中解決循環依賴是:三級緩存和提前暴露。其實最核心的是實例化和初始化分開進行。

spring三級緩存源碼:

    //一級緩存,保存beanName和創建Bean直接實例的關系(保存成熟對象)
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
    //三級緩存,保存beanName和創建Bean的工廠之間的關系(第二個是一個函數式接口的類型)
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
    //二級緩存,保存保存beanName和創建Bean直接實例的關系(半成品對象)
    private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);

簡述下過程:

A首先完成了初始化的第一步,而且將本身提早曝光到singletonFactories中,此時進行初始化的第二步,發現本身依賴對象B,此時就嘗試去get(B),發現B尚未被create,因此走create流程,B在初始化第一步的時候發現本身依賴了對象A,因而嘗試get(A),嘗試一級緩存singletonObjects(確定沒有,由于A還沒初始化徹底),嘗試二級緩存earlySingletonObjects(也沒有),嘗試三級緩存singletonFactories,因為A經過ObjectFactory將本身提早曝光了,因此B可以經過ObjectFactory.getObject拿到A對象(半成品),B拿到A對象后順利完成了初始化階段一、二、三,徹底初始化以后將本身放入到一級緩存singletonObjects中。此時返回A中,A此時能拿到B的對象順利完成本身的初始化階段二、三,最終A也完成了初始化,進去了一級緩存singletonObjects中,因為B拿到了A的對象引用,因此B里面A對象完成了初始化。

?注意事項:

1.Spring只是解決了單例模式下屬性依賴的循環問題;Spring為了解決單例的循環依賴問題,使用了三級緩存。

2.多實例Bean是每次調用一次getBean都會執行一次構造方法并且給屬性賦值,根本沒有三級緩存,因此不能解決循環依賴。

原文鏈接:https://blog.csdn.net/weixin_71419462/article/details/126169103

欄目分類
最近更新