一、什么是回圈依賴?什么是三級快取?
【什么是回圈依賴】什么是回圈依賴很好理解,當我們代碼中出現,形如BeanA類中依賴注入BeanB類,BeanB類依賴注入A類時,在IOC程序中creaBean實體化A之后,發現并不能直接initbeanA物件,需要注入B物件,發現物件池里還沒有B物件,通過構建函式創建B物件的實體化,又因B物件需要注入A物件,發現物件池里還沒有A物件,就會套娃,
【三級快取】三級快取實際上就是三個Map物件,從存放物件的順序開始
三級快取singletonFactories存放ObjectFactory,傳入的是匿名內部類,ObjectFactory.getObject() 方法最侄訓呼叫getEarlyBeanReference()進行處理,回傳創建bean實體化的lambda運算式,
二級快取earlySingletonObjects存放bean,保存半成品bean實體,當物件需要被AOP切面代時,保存代理bean的實體beanProxy
一級快取(單例池)singletonObjects存放完整的bean實體
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

二、三級快取如何解決回圈依賴?
【如何解決回圈依賴】Spring解決回圈依賴的核心思想在于提前曝光,首先創建實體化A,并在三級快取singletonFactories中保存實體化A的lambda運算式以便獲取A實體,當我沒有回圈依賴和AOP時,這個三級快取singletonFactories是沒用在后續用到的,
但是當我A物件需要注入B物件,發現快取里還沒有B物件,創建B物件并又上述所說添加進三級快取singletonFactories,B物件需要注入A物件,這時從半成品快取里取到半成品物件A,通過快取的lambda運算式創建A實體物件,并放到二級快取earlySingletonObjects中,
此時B物件可以注入A物件實體和初始化自己,之后將完成品B物件放入完成品快取singletonObjects,但是當有aop時,B物件還沒有把完成品B物件放入完成品快取singletonObjects中,B物件初始化后需要進行代理物件的創建,此時需要從singletonFactories獲取bean實體物件,進行createProxy創建代理類操作,這是會把proxy&B放入二級快取earlySingletonObjects中,這時候才會把完整的B物件放入完成品一級快取也叫單例池singletonObjects中,回傳給A物件,
A物件繼續注入其他屬性和初始化,之后將完成品A物件放入完成品快取,

三、使用二級快取能不能解決回圈依賴?
一定是不行,我們只保留二級快取有兩個可能性保留一二singletonObjects和earlySingletonObjects,或者一三singletonObjects和singletonFactories
【只保留一二singletonObjects和earlySingletonObjects】
流程可以這樣走:實體化A ->將半成品的A放入earlySingletonObjects中 ->填充A的屬性時發現取不到B->實體化B->將半成品的B放入earlySingletonObjects中->從earlySingletonObjects中取出A填充B的屬性->將成品B放入singletonObjects,并從earlySingletonObjects中洗掉B->將B填充到A的屬性中->將成品A放入singletonObjects并洗掉earlySingletonObjects,
這樣的流程是執行緒安全的,不過如果A上加個切面(AOP),這種做法就沒法滿足需求了,因為earlySingletonObjects中存放的都是原始物件,而我們需要注入的其實是A的代理物件,
【只保留一三singletonObjects和singletonFactories】
流程是這樣的:實體化A ->創建A的物件工廠并放入singletonFactories中 ->填充A的屬性時發現取不到B->實體化B->創建B的物件工廠并放入singletonFactories中->從singletonFactories中獲取A的物件工廠并獲取A填充到B中->將成品B放入singletonObjects,并從singletonFactories中洗掉B的物件工廠->將B填充到A的屬性中->將成品A放入singletonObjects并洗掉A的物件工廠,
同樣,這樣的流程也適用于普通的IOC已經有并發的場景,但如果A上加個切面(AOP)的話,這種情況也無法滿足需求,
因為拿到ObjectFactory物件后,呼叫ObjectFactory.getObject()方法最侄訓呼叫getEarlyBeanReference()方法,getEarlyBeanReference這個方法每次從三級快取中拿到singleFactory物件,執行getObject()方法又會產生新的代理物件
所有這里我們要借助二級快取來解決這個問題,將執行了singleFactory.getObject()產生的物件放到二級快取中去,后面去二級快取中拿,沒必要再執行一遍singletonFactory.getObject()方法再產生一個新的代理物件,保證始終只有一個代理物件,
getSingleton()、getEarlyBeanReference() 原始碼如下
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName); // 先從一級快取拿
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName); // 拿二級快取
if (singletonObject == null && allowEarlyReference) {
// 拿三級快取
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 最侄訓呼叫傳入的匿名內部類getEarlyBeanReference()方法,這里面沒呼叫一次會生成一個新的代理物件
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/301516.html
標籤:java
上一篇:??高級JAVA開發必備技能??java8 新日期時間API((五)JSR-310:實戰+原始碼分析),5萬字詳解(JAVA 小虛竹,建議收藏)
