Spring IOC原始碼深度剖析:Spring IoC迴圈依賴問題
一、什麼是迴圈依賴
迴圈依賴其實就是迴圈引⽤,也就是兩個或者兩個以上的 Bean 互相持有對⽅,最終形成閉環。⽐如A依賴於B,B依賴於C,C⼜依賴於A。
注意,這⾥不是函式的迴圈調⽤,是物件的相互依賴關係。迴圈調⽤其實就是⼀個死迴圈,除⾮有終結條件。
Spring中迴圈依賴場景有:
- 構造器的迴圈依賴(構造器注⼊)
- Field 屬性的迴圈依賴(set注⼊)
其中,構造器的迴圈依賴問題⽆法解決,只能丟擲
BeanCurrentlyInCreationException
異常,在解決屬性迴圈依賴時,spring採⽤的是提前暴露物件的⽅法。
二、迴圈依賴處理機制
-
單例 bean 構造器引數迴圈依賴(⽆法解決)
-
prototype 原型 bean迴圈依賴(⽆法解決)
對於原型bean的初始化過程中不論是透過構造器引數迴圈依賴還是透過
setXxx
⽅法產⽣迴圈依賴,Spring都 會直接報錯處理。
AbstractBeanFactory.doGetBean()
⽅法:
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
return (curVal != null &&
(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>)curVal).contains(beanName))));
}
在獲取bean之前如果這個原型bean正在被建立則直接丟擲異常。原型bean在建立之前會進⾏標記這個
beanName
正在被建立,等建立結束之後會刪除標記
try {
//建立原型bean之前新增標記 beforePrototypeCreation(beanName);
//建立原型bean prototypeInstance = createBean(beanName, mbd, args);}finally {
//建立原型bean之後刪除標記 afterPrototypeCreation(beanName);
}
總結:Spring 不⽀持原型 bean 的迴圈依賴。
單例bean透過
setXxx
或者
@Autowired
進⾏迴圈依賴
Spring 的迴圈依賴的理論依據基於 Java 的引⽤傳遞,當獲得物件的引⽤時,物件的屬性是可以延後設定的,但是構造器必須是在獲取引⽤之前
Spring透過
setXxx
或者
@Autowired
⽅法解決迴圈依賴其實是透過提前暴露⼀個
ObjectFactory
物件來完成的,簡單來說ClassA在調⽤構造器完成物件初始化之後,在調⽤ClassA的
setClassB
⽅法之前就把ClassA例項化的物件透過
ObjectFactory
提前暴露到Spring容器中。
- Spring容器初始化ClassA透過構造器初始化物件後提前暴露到Spring容器。
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");
}
//將初始化後的物件提前已ObjectFactory物件注⼊到容器中 addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
-
ClassA調⽤setClassB⽅法,Spring⾸先嚐試從容器中獲取ClassB,此時ClassB不存在Spring容器中。
-
Spring容器初始化ClassB,同時也會將ClassB提前暴露到Spring容器中
-
ClassB調⽤setClassA⽅法,Spring從容器中獲取ClassA ,因為第⼀步中已經提前暴露了ClassA,因此可以獲取到ClassA例項
-
ClassA透過spring容器獲取到ClassB,完成了物件初始化操作。
-
這樣ClassA和ClassB都完成了物件初始化操作,解決了迴圈依賴問題。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69964492/viewspace-2765336/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Spring IoC - 迴圈依賴Spring
- Spring原始碼分析之IOC迴圈依賴Spring原始碼
- spring原始碼深度解析— IOC 之 迴圈依賴處理Spring原始碼
- 從原始碼層面深度剖析Spring迴圈依賴原始碼Spring
- Spring原始碼分析(三)手寫簡單的IOC容器和解決迴圈依賴問題Spring原始碼
- Spring Ioc原始碼分析系列--自動注入迴圈依賴的處理Spring原始碼
- Spring IOC——依賴注入Spring依賴注入
- spring原始碼解析之IOC容器(三)——依賴注入Spring原始碼依賴注入
- Spring原始碼分析:Spring的迴圈依賴分析Spring原始碼
- Spring原始碼剖析1:初探Spring IOC核心流程Spring原始碼
- Spring原始碼剖析2:初探Spring IOC核心流程Spring原始碼
- .netcore ioc 迴圈依賴問題及其相關思考之DispatchProxyNetCore
- 3.1 spring5原始碼系列--迴圈依賴 之 手寫程式碼模擬spring迴圈依賴Spring原始碼
- 死磕Spring之IoC篇 - 單例 Bean 的迴圈依賴處理Spring單例Bean
- 面試題:Spring 的迴圈依賴問題面試題Spring
- Spring迴圈依賴Spring
- 【Spring系列】- Spring迴圈依賴Spring
- 3.2spring原始碼系列----迴圈依賴原始碼分析Spring原始碼
- 【spring原始碼系列】之【Bean的迴圈依賴】Spring原始碼Bean
- 【spring】迴圈依賴 Java Vs SpringSpringJava
- Spring5.0原始碼學習系列之淺談迴圈依賴問題Spring原始碼
- spring原始碼深度解析— IOC 之 bean 建立Spring原始碼Bean
- spring原始碼閱讀筆記09:迴圈依賴Spring原始碼筆記
- Spring——為什麼會有迴圈依賴(原始碼)Spring原始碼
- Spring原始碼分析(二)bean的例項化和IOC依賴注入Spring原始碼Bean依賴注入
- Spring原始碼剖析3:Spring IOC容器的載入過程Spring原始碼
- spring解決迴圈依賴Spring
- Spring迴圈依賴+案例解析Spring
- Spring中的迴圈依賴Spring
- 【Spring】快速理解迴圈依賴Spring
- spring 詳細講解(ioc,依賴注入,aop)Spring依賴注入
- Spring的迴圈依賴,學就完事了【附原始碼】Spring原始碼
- Spring原始碼分析之迴圈依賴及解決方案Spring原始碼
- Spring原始碼--debug分析迴圈依賴--構造器注入Spring原始碼
- 【spring原始碼】十、AOP迴圈依賴、三級快取Spring原始碼快取
- spring原始碼深度解析— IOC 之 屬性填充Spring原始碼
- Spring 迴圈依賴的三種方式(三級快取解決Set迴圈依賴問題)Spring快取
- Spring:原始碼解讀Spring IOC原理Spring原始碼