Spring原始碼解析之迴圈依賴處理(5)

2021-09-03 07:59:31 字數 2810 閱讀 4213

什麼是迴圈依賴?

迴圈依賴其實就是兩個或者兩個以上的bean,互相引用對方,形成閉環,如a--->b,b--->c,c--->a。這樣的依賴就是迴圈依賴。而迴圈依賴在正常的情況下就是乙個死迴圈,a的初始化為引起b的初始化,b的初始化會觸發c的初始化,而c的初始化會觸發a的初始化,死迴圈了。

spring的迴圈依賴有兩種:

構造器的迴圈依賴

屬性的迴圈依賴      

構造器的迴圈依賴是沒有spring的無法解決,所以會丟擲異常。我們分析的都是基於屬性的迴圈依賴。

迴圈依賴的處理。

第一次處理迴圈依賴的地方是dogetbean()方法中的:

object sharedinstance = getsingleton(beanname);
protected object getsingleton(string beanname, boolean allowearlyreference) }}

}return singletonobject;

}

這個方法其實之前分析過的,我們可以這樣理解迴圈依賴有三層的快取。

singletonobjects:一級快取,存放的是beanname和bean例項。

earlysingletonobjects:二級快取,存放的是beanname和已經被初始化但是沒有建立完成的bean例項。也就是允許提前**的bean的例項

singletonfactory:**快取,存放的是beanname和objectfactory工廠。

通過這三層快取的有效的解決了spring的屬性迴圈依賴問題。這個方法還有兩個方法要解析。

issingletoncurrentlyincreation方法:判斷bean是否在建立中。

allowearlyreference:判斷bean是否可以被提前**。

getsingletion()這個邏輯:從一級快取singletonobjects中獲取,如果沒有當前beanname的是例項並且正在建立中,那麼就從二級快取中earlysingletonobjects獲取,如果還是沒有獲取到,那麼從**快取中獲取並呼叫getobject()去獲取bean的例項,並將其加入二級快取earlysingletonobjects,從**快取singletonfactory中刪除。

那麼**快取的新增是從**開始的。追蹤createbean()方法,在docreatebean()方法中

//判讀條件

boolean earlysingletonexposure = (mbd.issingleton() && this.allowcircularreferences && issingletoncurrentlyincreation(beanname));

addsingletonfactory(beanname, () -> getearlybeanreference(beanname, mbd, bean))

當earlysingletonexposure==true時,會去執行addsingletonfactory()方法。

那滿足新增**快取的的條件是:

mbd.issingleton():單例模式

this.allowcircularreferences:該bean允許被提前**

issingletoncurrentlyincreation(beanname):正在處於建立中

protected void addsingletonfactory(string beanname, objectfactory<?> singletonfactory) 

}}

這個段**是在createbeaninstance()之後,bean的例項是已經建立出來,但是並沒有屬性進行初始化。但是並不妨礙其他bean

對這個bean的物件引用。

下面分析一級快取的新增邏輯在在類 defaultsingletonbeanregistry 中可以發現這個addsingleton()方法:

addsingleton(beanname, singletonobject)方法在this.singletonobjects.get(beanname)之後

protected void addsingleton(string beanname, object singletonobject) 

}

在spring解決迴圈依賴的方案中:spring在建立bean的時候並不是等完全完成,而是在建立過程中將建立的bean的objectfactory提前**(加入**快取),這樣另外的bean需要依賴的bean,可以直接使用objectfactory的getobejct獲取。

到這裡,關於 spring 解決 bean 迴圈依賴就已經分析完畢了。最後來描述下就上面那個迴圈依賴 spring 解決的過程:首先 a 完成初始化第一步並將自己提前**出來(通過 objectfactory 將自己提前**),在初始化的時候,發現自己依賴物件 b,此時就會去嘗試 get(b),這個時候發現 b 還沒有被建立出來,然後 b 就走建立流程,在 b 初始化的時候,同樣發現自己依賴 c,c 也沒有被建立出來,這個時候 c 又開始初始化程序,但是在初始化的過程中發現自己依賴 a,於是嘗試 get(a),這個時候由於 a 已經新增至快取中(一般都是新增至**快取 singletonfactories ),通過 objectfactory 提前**,所以可以通過objectfactory.getobject()拿到 a 物件,c 拿到 a 物件後順利完成初始化,然後將自己新增到一級快取中,回到 b ,b 也可以拿到 c 物件,完成初始化,a 可以順利拿到 b 完成初始化。到這裡整個鏈路就已經完成了初始化過程了。

spring原始碼解析 單例Bean迴圈依賴解決方法

0x01 前提條件 0x02 解決方法 1 bean工廠在建立bean之前會嘗試從快取中拿到bean,bean工廠中定義了 快取 singletonobjects 一級快取 earlysingletonobjects 二級快取 singletonfactories 快取 以下 片段摘自default...

Spring原始碼深度解析之迴圈依賴

如果大家看過spring例項化bean的核心方法 docreatebean,大家會發現例項化bean是乙個非常複雜的過程,而這其中最難以理解的就是對迴圈依賴的解決,這裡我們就對此點問題進行一下說明。什麼是迴圈依賴 首先我們要弄懂迴圈依賴是什麼。迴圈依賴就是迴圈引用,就是兩個或者多個bean相互之間持...

Spring原始碼解析之 Aop原始碼解析(2)

spring aop 更多的是oop開發模式的乙個補充,幫助oop以更好的方式來解決對於需要解決業務功能模組之上統一管理 的功能 以一副圖來做為aop功能的說明更直觀些。對於類似系統的安全檢查,系統日誌,事務管理等相關功能,物件導向的開發方法並沒有更好的解決方法 aop引入了一些概念。更多的是spr...