什麼是迴圈依賴?
迴圈依賴其實就是兩個或者兩個以上的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...