Spring如何解決循環(huán)依賴
點擊上方藍色字體,選擇“標(biāo)星公眾號”
優(yōu)質(zhì)文章,第一時間送達
作者 | MXC肖某某
來源 | urlify.cn/ZriUjy
一、什么是循環(huán)依賴
多個bean之間相互依賴,形成了一個閉環(huán)。比如:A依賴于B、B依賴于c、c依賴于A
通常來說,如果問spring容器內(nèi)部如何解決循環(huán)依賴, 一定是指默認的單例Bean中,屬性互相引用的場景。也就是說,Spring的循環(huán)依賴,是Spring容器注入時候出現(xiàn)的問題。

二、Spring如何解決循環(huán)依賴
1,Spring中單例Bean的三級緩存

第一級緩存〈也叫單例池)singletonObjects:存放已經(jīng)經(jīng)歷了完整生命周期的Bean對象
第二級緩存: earlySingletonObjects,存放早期暴露出來的Bean對象,Bean的生命周期未結(jié)束(屬性還未填充完整)
第三級緩存: Map<String, ObiectFactory<?>> singletonFactories,存放可以生成Bean的工廠
2,Spring中Bean的生命周期


3,Bean初始化主要方法

getSingleton:希望從容器里面獲得單例的bean,沒有的話
doCreateBean: 沒有就創(chuàng)建bean
populateBean: 創(chuàng)建完了以后,要填充屬性
addSingleton: 填充完了以后,再添加到容器進行使用
4,具體說明
A創(chuàng)建過程中需要B,于是A將自己放到三級緩存里面,去實例化B
B實例化的時候發(fā)現(xiàn)需要A,于是B先查一級緩存,沒有,再查二級緩存,還是沒有,再查三級緩存,找到了A然后把三級緩存里面的這個A放到二級緩存里面,并刪除三級緩存里面的A
B順利初始化完畢,將自己放到一級緩存里面(此時B里面的A依然是創(chuàng)建中狀態(tài))然后回來接著創(chuàng)建A,此時B已經(jīng)創(chuàng)建結(jié)束,直接從一級緩存里面拿到B,然后完成創(chuàng)建,并將A放到一級緩存中。
5,圖解

三、為什么使用三級緩存
1,使用一級緩存
實例化A -> 將半成品的A放入singletonObjects中->填充A的屬性時發(fā)現(xiàn)取不到B->實例化B->從singletonObjects中取出A填充B的屬性->將成品B放入singletonObjects->將B填充到A的屬性中->將成品A放入singletonObjects。
問題:這種基本流程是通的,但是如果在整個流程進行中,有另一個線程要來取A,那么有可能拿到的只是一個屬性都為null的半成品A,這樣就會有問題。
2,使用二級緩存
a)使用singletonObjects和earlySingletonObjects
成品放在singletonObjects中,半成品放在earlySingletonObjects中
流程可以這樣走:實例化A ->將半成品的A放入earlySingletonObjects中 ->填充A的屬性時發(fā)現(xiàn)取不到B->實例化B->將半成品的A放入earlySingletonObjects中->從earlySingletonObjects中取出A填充B的屬性->將成品B放入singletonObjects,并從earlySingletonObjects中刪除B->將B填充到A的屬性中->將成品A放入singletonObjects并刪除earlySingletonObjects。
問題:這樣的流程是線程安全的,不過如果A上加個切面(AOP),這種做法就沒法滿足需求了,因為earlySingletonObjects中存放的都是原始對象,而我們需要注入的其實是A的代理對象。
b)使用singletonObjects和singletonFactories
成品放在singletonObjects中,半成品通過singletonFactories來獲取
流程是這樣的:實例化A ->創(chuàng)建A的對象工廠并放入singletonFactories中 ->填充A的屬性時發(fā)現(xiàn)取不到B->實例化B->創(chuàng)建B的對象工廠并放入singletonFactories中->從singletonFactories中獲取A的對象工廠并獲取A填充到B中->將成品B放入singletonObjects,并從singletonFactories中刪除B的對象工廠->將B填充到A的屬性中->將成品A放入singletonObjects并刪除A的對象工廠。
問題:這樣的流程也適用于普通的IOC,但如果A上加個切面(AOP)的話,這種情況也無法滿足需求,因為每次通過singletonFactories.getObject()獲取的代理對象都不同。
粉絲福利:Java從入門到入土學(xué)習(xí)路線圖
??????

??長按上方微信二維碼 2 秒
感謝點贊支持下哈 
