"a" class
="com.demo.circularreference.a"
>
name
="b"
ref="b"
/>
bean
>
"b" class
="com.demo.circularreference.b"
>
name
="a"
ref="a"
/>
bean
>
public
classa}
public
class
b}
spring中將迴圈依賴的處理分為了3種情況
通過構造器注入形成的迴圈依賴是無法解決的,容器中會丟擲beancurrentlyincreationexception異常。
首先需要明確的一點是,容器會標識乙個當前正在建立的bean,將它記錄在快取singletonscurrentlyincreation中。
public
class
defaultsingletonbeanregistry
extends
******aliasregistry
implements
singletonbeanregistry
//將bean id加入singletonscurrentlyincreation,如果加入失敗則丟擲illegalstateexception
beforesingletoncreation
(beanname)
;//例項化單例bean
singletonobject = singletonfactory.
getobject()
;//將bean id從singletonscurrentlyincreation中移除,如果移除失敗則丟擲beancurrentlyincreationexception
aftersingletoncreation
(beanname)
; newsingleton =
true;if
(newsingleton)
}return singletonobject;
}}
構造器注入和setter注入的不同之處在於,構造器注入的方式在通過構造方法例項化bean的時候就直接尋找依賴注入了,而setter注入需要在例項化步驟中先通過預設的無參構造方法例項化bean以後,再在後續方法中通過setter方法尋找依賴注入。這就導致通過構造器注入例項化a的時候,會直接去尋找依賴b,而依賴b又會去尋找依賴a,此時a和b的id都已經存在於快取singletonscurrentlyincreation 中,當再次尋找a想加入快取的時候,就會新增失敗進而丟擲beancurrentlyincreationexception異常。
一般是指單例bean之間能構成迴圈依賴。承接上文來說,當單例a例項化完成後會快取在singletonfactories中。這樣在setter注入b的時候,b需要去獲取a,在dogetbean方法開頭通過getsingleton中就可以直接返回。
protected object docreatebean
(final string beanname,
final rootbeandefinition mbd,
final
@nullable object[
] args)
throws beancreationexception ()
; class<?(
);if(beantype != nullbean.
class
)//讓例項化後的bean早早暴露出來,方便setter注入時依賴bean能提前發現依賴
boolean earlysingletonexposure =
(mbd.
issingleton()
&&this
.allowcircularreferences &&
issingletoncurrentlyincreation
(beanname));
if(earlysingletonexposure)
//加入到快取singletonfactories中
addsingletonfactory
(beanname,()
->
getearlybeanreference
(beanname, mbd, bean));
} object exposedobject = bean;
//setter注入
populatebean
; exposedobject =
initializebean
(beanname, exposedobject, mbd)
;return exposedobject;
}
protected
t dogetbean
(final string name,
@nullable
final class
requiredtype,
@nullable
final object[
] args,
boolean typecheckonly)
throws bean***ception }}
}return singletonobject;
}
對於兩個原型bean是無法處理迴圈依賴的。在dogetbean方法中就存在校驗。
protected
t dogetbean
(final string name,
@nullable
final class
requiredtype,
@nullable
final object[
] args,
boolean typecheckonly)
throws bean***ception
else
實際原因也很簡單,原型bean不會被記錄在快取singletonfactory中。因為迴圈依賴中,當a去尋找b,b也會去尋找a,但是此時b找到的a不再是之前的a,而是乙個新的a (prototype),這就導致這樣的依賴關係沒有終點,造成了死迴圈。
但是在某些場景下單例bean和原型bean是能構成迴圈依賴的。
singleton beana和prototype beanb 兩者構成迴圈依賴,當執行getbean方法執行存在先後順序的時候,先通過getbean方法獲取a的時候是可行的,但是先通過getbean方法獲取b就不行了。因為先通過getbean方法獲取a的時候,先例項化了單例a,再注入原型b,原型b中可以找到單例a,就能構成一次有終點的迴圈依賴。反之,先通過getbean方法獲取b的時候,先例項化原型b,再注入單例a,單例a又依賴於乙個新的原型b,這樣就無法構成迴圈依賴了。因此在這個場景下,執行例項化的順序十分重要。
spring迴圈依賴問題
在開始介紹各種情況之前,首先要了解以下三個知識點 spring中依賴注入的方式有兩種,屬性注入與構造器注入。上面的 中,類a就是通過屬性注入的方式注入了b,類b是通過構造器注入的方式注入了a。spring中的bean根據作用域的不同,可以大體分為兩類,singleton和prototype。sing...
Spring迴圈依賴問題(筆記)
a類中有成員變數b類的物件。b類中也有成員變數a類的物件。簡單來說就,就是如下情況 class a class b 在一開始的開始 也就是程式第一次獲取a的例項時,需要從spring容器單例池中獲取。但此時單例池中還沒有a的例項,所以要new 乙個a物件。在a例項 建立和初始化的時候,要獲取成員變數...
spring 迴圈依賴
構造器依賴無法解決,使用 快取解決field屬性依賴。a的屬性依賴b,b的屬性依賴a 建立a,設定依賴屬性b,發現b沒有建立,建立b,設定依賴屬性a,先從一級快取singletonobjects中去獲取。如果獲取到就直接return 如果獲取不到或者物件正在建立中 issingletoncurren...