Spring IOC 容器解決循環依賴問題主要涉及到幾個關鍵的緩存和對象創建過程中的處理邏輯。以下是對循環依賴問題進行深度剖析的概述:
-
循環依賴的背景
循環依賴發生在兩個或多個Bean相互依賴對方,形成一個閉環。這可能是直接的,比如Bean A依賴Bean B,Bean B又依賴Bean A;或者是間接的,比如Bean A依賴Bean B,Bean B依賴Bean C,Bean C又依賴Bean A。循環依賴會導致在Bean創建過程中出現無限遞歸。 -
Spring IOC容器中的緩存
為了解決循環依賴,Spring使用了多個緩存來存儲Bean的不同狀態:
singletonObjects:存放完全初始化好的單例Bean。
earlySingletonObjects:存放原始的Bean對象(尚未填充屬性),用于解決循環依賴。
singletonFactories:存放Bean工廠對象,用于生成Bean的早期引用。
3. Bean創建過程
當Spring容器創建一個Bean時,它會經歷以下步驟:
實例化Bean:首先,容器會實例化Bean,此時Bean的屬性還未被填充。
注冊Bean的早期引用:實例化后,容器將Bean的早期引用(未填充屬性的實例)注冊到earlySingletonObjects和singletonFactories緩存中。
屬性填充:然后,容器會填充Bean的屬性,解析其他Bean的依賴。
初始化Bean:最后,Bean會被初始化,完成所有生命周期回調,然后被放入singletonObjects緩存中供后續使用。
4. 解決循環依賴的關鍵
當一個Bean在屬性填充過程中需要引用另一個尚未完全初始化的Bean時,Spring容器會:
檢查singletonFactories緩存,看是否可以獲取到對方Bean的早期引用。
如果可以,容器會使用這個早期引用來完成當前Bean的屬性填充,從而打破循環。
5. 源碼分析
在DefaultSingletonBeanRegistry類的getSingleton方法中,Spring容器處理循環依賴的邏輯非常關鍵。如果嘗試獲取的Bean正在創建中(即在singletonObjects中不存在,但在earlySingletonObjects中存在),容器會嘗試從singletonFactories獲取早期引用,并將其放入earlySingletonObjects中,然后繼續Bean的創建過程。
- 限制和例外
Spring只能解決單例作用域的循環依賴問題。
對于原型作用域的Bean,Spring無法解決循環依賴,會拋出BeanCurrentlyInCreationException異常。 - 總結
Spring IOC容器通過使用緩存和對象工廠來處理循環依賴問題,確保了Bean的創建過程不會陷入無限循環。這種機制允許Bean在完全初始化之前,就可以被其他Bean引用,從而打破了循環依賴。
通過上述分析,我們可以看到Spring框架如何巧妙地解決了循環依賴問題,確保了容器的穩定性和Bean生命周期的正常管理。