Spring迴圈依賴

2023-02-07 06:00:48

Spring迴圈依賴面試中也會被常常問到。但是它的整個過程很多人都不知道,什麼叫回圈依賴呢。多個Bean之間相互依賴,形成一個閉環。如下圖(A,B,C分別為Spring容器中3個Bean)就能很好的描述。(PS必須保證預設的Bean都是單例的迴圈依賴才成立)。

 

上面是對Spring迴圈依賴的簡單解釋,下圖是Spring官網說明。

 

上圖中重點翻譯就是:迴圈依賴不支援構造方法的注入,使用構造方法注入會丟擲BeanCurrentlyInCreationException異常 。Spring不推薦構造注入,只支援setter注入。

Spring是怎麼支援和解決迴圈依賴的呢?

 

它目前解決的方案是靠自身容器中的3個Map來解決的,也稱為三級快取,如下圖:

 

第一級快取(也叫單例池)singleObjects:存放已經經歷完整生命週期的Bean物件。

第二級快取:earlySingletonObjects,存放早期暴漏的Bean物件,Bean週期未結束(屬性未完全填充)。

第三級快取:singletonFactories,存放可以生成Bean的工廠。

那麼下面我們就通過原始碼來說明Spring是如何通過上面三級快取來解決迴圈依賴的,我們就用2個物件來演示和理解迴圈依賴。

1:A建立過程中需要B,於是A將自己放到三級快取裡面,去範例化B。

2:B範例化的時候發現需要A,於是B先查一級快取,沒有再查二級快取,還是沒有,再查三級快取,找到了A,然後把三級快取裡面的A放到二級快取裡面,並刪除三級快取裡面的A。

3:B順利完成初始化,將自己放到一級快取裡面(此時B裡面的A依然是建立中的狀態)然後接著回來建立A,此時B已經建立結束,直接從一級快取裡面拿B,並將A自己放到一級快取裡面。

原始碼分析主要關注如下方法的流程:

 

 

 

 

1:呼叫doCreateBean()方法,想要獲取a ,於是呼叫getSingleton()方法從快取中獲取a 。

 

2:getSingleton()方法從一級快取中找,沒有找到返回null。

3:如果getSingleton()方法中獲取到的a為null ,於是走對應的邏輯處理,呼叫getSingleton的過載的方法(引數為ObjectFactory)。

 

4:在getSingleton()中將a新增到一個集合中,用於標記a正在建立中,然後呼叫匿名內部類的creatBean方法。

5:進入AbstractAutowireCapableBeanFactory的doCreateBean,建立出a的範例然後將a新增到三級快取中。

 

6:對a進行屬性的填充,此時檢測到a依賴於b,於是開始找b 。

 

 

7:找b的時候呼叫doGetBean()方法和上面建立a的過程一樣,到快取中找b,沒有則建立,然後給b填充屬性。

 

8:此時b依賴於a,呼叫getSingleton獲取a,依次從一級,二級,三級快取中找,此時從三級快取中獲取a的建立工廠,通過建立工廠獲取到singeltonObject,此時這個singletonObject指向的就是上面的doCreateBean方法中獲取的範例化的a。

 

 

9:這樣b就獲取到了a的依賴,於是b順利完成了範例化,並將a從三級快取移到二級快取中。

 

10:隨後a繼續屬性填充的工作,此時也獲取了b,然後a也就完成了建立,回到getSingleton方法中繼續執行,將a從二級快取移動到一級快取。

 

具體為什麼用三級快取不用二級快取去解決,後面章節分析,歡迎轉發,評論,點贊

微信公眾號搜尋:程式設計師xiaozhang 。如果遇到Spring的問題也可以私信我 能幫忙解決的儘量解決。