Spring 之 迴圈依賴詳解

2021-10-06 15:54:40 字數 3619 閱讀 1487

如果 class a 中依賴了 class b並且class b 中也依賴了class a,形成乙個閉環就會產生迴圈依賴的問題。

構造器注入方式的迴圈依賴,無法解決;

setter注入方式的迴圈依賴,解決方式:

spring先用構造器例項化bean物件,將例項化結束的物件放到乙個map中,並且spring提供獲取這個未設定屬性的例項化物件的引用方法;

在進行屬性注入的時候,依次獲取到對應的bean例項物件進行注入;

在 abstractbeanfactory 的 dogetbean 方法中,會首先通過快取中去查詢單例 bean 物件。呼叫 getsingleton 方法,原始碼如下:

protected object getsingleton

(string beanname,

boolean allowearlyreference)}}

}return singletonobject;

}

從這個方法上我們可以看到 spring 使用**快取解決迴圈依賴問題,每個快取儲存例項物件引用的不同生命週期:

呼叫 createbeaninstance 方法進行例項化物件

呼叫 populatebean 方法進行依賴注入

呼叫 initializebean 方法執行 beanpostprocessor 後置處理器

我們來看看例項化完之後在什麼時候儲存到 singletonfactories 快取中,在 abstractautowirecapablebeanfactory.docreatebean() 方法中。

protected object docreatebean

(final string beanname,

final rootbeandefinition mbd,

final

@nullable object[

] args)

throws beancreationexception

if//...

// 向容器中快取單例模式的bean物件,以防止迴圈引用

boolean earlysingletonexposure =

(mbd.

issingleton()

&&this

.allowcircularreferences &&

issingletoncurrentlyincreation

(beanname));

if(earlysingletonexposure)

//為避免後期迴圈依賴,盡早持有物件的引用

addsingletonfactory

(beanname,()

->

getearlybeanreference

(beanname, mbd, bean));

}//...

}protected

void

addsingletonfactory

(string beanname, objectfactory<

?> singletonfactory)

}}

可以看到在 createbeaninstance 方法例項化物件之後(此時還未進行依賴注入)就會暴露到 singletonfactories **快取集合中,以解決屬性注入的迴圈引用問題。

在 abstractbeanfactory 的 dogetbean 方法中,呼叫 createbean 方法

//建立單例模式的bean的例項物件

if(mbd.

issingleton()

)catch

(bean***ception ex)})

;//獲取給定bean的例項物件,主要完成factorybean獲取例項化物件過程

bean =

getobjectforbeaninstance

(sharedinstance, name, beanname, mbd)

;}

繼續跟進 defaultsingletonbeanregistry.getsingleton() 方法,原始碼如下:

public object getsingleton

(string beanname, objectfactory<

?> singletonfactory)

if(logger.

isdebugenabled()

)beforesingletoncreation

(beanname)

;boolean newsingleton =

false

;boolean recordsuppressedexceptions =

(this

.suppressedexceptions == null);if

(recordsuppressedexceptions)

trycatch

(illegalstateexception ex)

}catch

(beancreationexception ex)

}throw ex;

}finally

aftersingletoncreation

(beanname);}

if(newsingleton)

}return singletonobject;}}

protected

void

addsingleton

(string beanname, object singletonobject)

}

從上面可看到,當 bean 例項初始化完成後將會刪除 singletonfactories 和 earlysingletonobjects 快取中的引用,新增到 singletonobjects 快取中。

最後梳理一下spring解決迴圈依賴的流程

1. 類 a 與 b 中屬性相互引用,造成迴圈依賴

2. a 例項化完成,將自己提前**到 singletonfactories 快取中

3. a 例項進行依賴注入,發現自己依賴物件 b,就嘗試獲取 b 例項引用

4. b 此時還沒初始化,先進行例項化並將自己**到 singletonfactories 快取中

5. b 例項進行依賴注入,發現自己依賴物件 a,就嘗試獲取 a 例項引用

6. 由於 a 例項尚未初始化完成,從 singletonobjects 中獲取不到,從 earlysingletonobjects 中獲取也沒有,最後從 singletonfactories 中獲取到

7. a 例項從 singletonfactories 中刪除,新增到 earlysingletonobjects 快取中去

8. b 例項拿到 a 例項引用後順利完成依賴注入及初始化,並將自己從 singletonfactories 快取中刪除,新增到 singletonobjects 快取中

9. a 例項獲取 b 例項引用後,a 例項也能繼續完成依賴注入及後續初始化操作

10. a 是從 earlysingletonobjects 中刪除,新增到 singletonobjects 快取中

在整個過程中,a 和 b 的例項引用並未改變過。只是在 bean 生命週期的不同階段。

Spring學習之迴圈依賴

很簡單,就是a物件依賴了b物件,b物件依賴了a物件。例如 a依賴了b class a b依賴了a class b那麼迴圈依賴是個問題嗎?如果不考慮spring,迴圈依賴並不是問題,因為物件之間相互依賴是很正常的事情。例如 a a newa b b newb a.b b b.a a 這樣,a,b就依賴...

spring 迴圈依賴

構造器依賴無法解決,使用 快取解決field屬性依賴。a的屬性依賴b,b的屬性依賴a 建立a,設定依賴屬性b,發現b沒有建立,建立b,設定依賴屬性a,先從一級快取singletonobjects中去獲取。如果獲取到就直接return 如果獲取不到或者物件正在建立中 issingletoncurren...

spring迴圈依賴

關於spring迴圈依賴網上有太多的例子,本文只是簡單的記錄一下。本文預設讀者熟悉spring核心之一控制反轉和依賴注入 在我們的開發過程中,我們基本上對迴圈依賴是無感且不用去考慮如何解決。如上圖中classa使用屬性注入了classb,classb使用屬性注入了classa。如上圖這就是產生了迴圈...