Spring可以解決迴圈依賴的條件

2021-10-09 22:15:25 字數 3977 閱讀 5500

在defaultsingletonbeanregistry類中,維護了三個注釋以cache of開頭的map,通過反省可以注意到,**快取與前兩級快取不太一樣,map中維護的值是objectfactory型別。

//單例快取池 beanname - instance 一級快取

private final mapsingletonobjects = new concurrenthashmap<>(256);

//bean的早期引用, bean name to bean instance 二級快取

private final mapearlysingletonobjects = new hashmap<>(16);

//單例工廠 beanname - objectfactory **快取

private final map> singletonfactories = new hashmap<>(16);

singletonobjects:一級快取,乙個單例bean【例項化+初始化】都完成之後,將會加入一級快取,也就是我們俗稱的單例池。

earlysingletonobjects:二級快取,用於存放【例項化完成,還沒初始化】的例項,提前暴露,用於解決迴圈依賴問題。

singletonfactories:**快取,存放單例物件工廠objectfactory,與二級快取不同的是,它可以應對產生**物件。

@functionalinte***ce //函式式介面

public inte***ce objectfactory

還有幾個比較重要的集合:

//bean被建立完成之後,註冊

private final set registeredsingletons = new linkedhashset<>(256);

//正在建立過程中的bean待的地兒,bean在開始建立的時候放入,知道建立完成將其移除

private final set singletonscurrentlyincreation =

collections.newsetfrommap(new concurrenthashmap<>(16));

getsingleton

abstractbeanfactory.dogetbean中將會出現兩個過載的getsingleton方法:

protected t dogetbean(…)

// 這個getsingleton方法非常關鍵。

//1、標註a正在建立中~

//2、呼叫singletonobject = singletonfactory.getobject();(實際上呼叫的是createbean()方法) 因此這一步最為關鍵

//3、標註此時例項已經建立完成

//4、執行addsingleton()新增進一級快取,

//同時移除二級和**快取,還有註冊

sharedinstance = getsingleton(beanname, () -> );getsingleton過載一號

protected object getsingleton(string beanname, boolean allowearlyreference)

我們的流程進行到abstractbeanfactory#dogetbean的時候,會執行object sharedinstance = getsingleton(beanname);,接著會執行getsingleton(beanname,true),一路跟進去,最終會進到defaultsingletonbeanregistry 的getsingleton方法,這個方法十分重要,我們具體看一看:

@nullable

protected object getsingleton(string beanname, boolean allowearlyreference) }}

}return singletonobject;

}先嘗試從一級快取中獲取,如果獲取到,表示這個物件已經【初始化+例項化】全部完成,當然,對於迴圈依賴的案例來說,這一步都是獲取不到的。

如果一級快取中獲取不到,沒關係,看看這個bean是不是正在建立中【已經開始例項化,但還沒有初始化完全】,如果是這個情況,就嘗試從二級快取中獲取。

如果都獲取不到,且allowearlyreference為true的時候,從**快取中取,**快取中存放的是objectfactory。

getsingleton過載二號

另外乙個singleton過載的方法:public object getsingleton(string beanname, objectfactory<?> singletonfactory)

public object getsingleton(string beanname, objectfactory<?> singletonfactory)

// 建立完成後將對應的beanname從singletonscurrentlyincreation移除

aftersingletoncreation(beanname);

} if (newsingleton)

}return singletonobject;}

addsingleton

protected void addsingleton(string beanname, object singletonobject)

}addsingletonfactory

abstractautowirecapablebeanfactory#docreatebean

在物件例項化完成,初始化之前進行:

protected object docreatebean(string beanname, rootbeandefinition mbd, @nullable object args)

throws beancreationexception

//表示是否提前暴露原始物件的引用,對於單例的bean,一般來說為true, 可以通過allowcircularreferences關閉迴圈引用解決迴圈依賴問題

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

//是否允許單例提前暴露

if (earlysingletonexposure)

//此時bean已經例項化完成, 開始準備初始化

// bean為原始物件

object exposedobject = bean;

try

//如果bean允許被早期暴露,進入**

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

getearlybeanreference

前面談到了這個方法,還沒有細說:

//是否允許單例提前暴露

if (earlysingletonexposure)

它實際上就是呼叫了後置處理器的getearlybeanreference,而真正實現了這個方法的後置處理器只有abstractautoproxycreator,與aop相關,也就是說,在不考慮aop的情況下,這個方法壓根就和沒呼叫似的。這裡我們也能更加明確,**快取出現很大程度上也是為了更好處理**物件。

protected object getearlybeanreference(string beanname, rootbeandefinition mbd, object bean)

}return exposedobject;

}我們可以跟進去看一看:

//abstractautoproxycreator

@override

public object getearlybeanreference(object bean, string beanname)

亞馬遜測評 www.yisuping.com

spring解決迴圈依賴

或者原型 prototype 的場景是不支援迴圈依賴的,丟擲異常。基於構造器的迴圈依賴,是不存在的。那麼預設單例的屬性注入場景,spring是如何支援迴圈依賴的?首先,spring內部維護了三個map,也就是我們通常說的 快取。在spring的defaultsingletonbeanregistry...

spring解決迴圈依賴

之前面試有被問到過,面試官很調皮,我擅長的點沒有問,然後抽了乙個點讓我回答,這個點考察了原始碼的理解,當時只是大概記得是提前暴露,但是細節答得有些粗糙,特補充一下,protected object getsingleton string beanname,boolean allowearlyrefe...

spring迴圈依賴的解決

當a類中有b屬性,b類中有a屬性的時候,就會產生迴圈依賴。a在例項化的時候,引用了b,但是b麼有例項化,所以就會先例項化b,這個時候發現b又引用了a,但是a還沒有例項化,所以就造成了迴圈依賴。我們來看看spring是如何解決的 public class classa public classa pu...