在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...