亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何理解Java Spring三級緩存和循環依賴

發布時間:2021-09-24 15:12:14 來源:億速云 閱讀:111 作者:柒染 欄目:開發技術

今天就跟大家聊聊有關如何理解Java Spring三級緩存和循環依賴,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。

一、什么是循環依賴?什么是三級緩存?

【什么是循環依賴】什么是循環依賴很好理解,當我們代碼中出現,形如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);

如何理解Java Spring三級緩存和循環依賴

二、三級緩存如何解決循環依賴?

【如何解決循環依賴】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對象放入完成品緩存。

如何理解Java Spring三級緩存和循環依賴

三、使用二級緩存能不能解決循環依賴?

一定是不行,我們只保留二級緩存有兩個可能性保留一二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;
	}

看完上述內容,你們對如何理解Java Spring三級緩存和循環依賴有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

姜堰市| 毕节市| 德化县| 贞丰县| 仪陇县| 且末县| 德保县| 潜江市| 尚义县| 奉节县| 新昌县| 昭通市| 河津市| 台前县| 华池县| 龙岩市| 大理市| 怀远县| 英超| 东山县| 上栗县| 邹城市| 巴楚县| 南和县| 凉城县| 鄂托克旗| 柳林县| 杭锦旗| 荔浦县| 京山县| 全南县| 体育| 营山县| 广德县| 沁源县| 云浮市| 张家港市| 巴塘县| 枣强县| 许昌市| 湛江市|