欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

關(guān)于Java Spring三級(jí)緩存和循環(huán)依賴的深入理解

 更新時(shí)間:2021年09月20日 11:18:02   作者:小明の學(xué)習(xí)心得  
對于循環(huán)依賴,我相信讀者無論只是聽過也好,還是有過了解也好,至少都有所接觸。但是我發(fā)現(xiàn)目前許多博客對于循環(huán)依賴的講解并不清楚,都提到了Spring的循環(huán)依賴解決方案是三級(jí)緩存,但是三級(jí)緩存每一級(jí)的作用是什么,很多博客都沒有提到,本篇文章帶你深入了解

一、什么是循環(huán)依賴?什么是三級(jí)緩存?

【什么是循環(huán)依賴】什么是循環(huán)依賴很好理解,當(dāng)我們代碼中出現(xiàn),形如BeanA類中依賴注入BeanB類,BeanB類依賴注入A類時(shí),在IOC過程中creaBean實(shí)例化A之后,發(fā)現(xiàn)并不能直接initbeanA對象,需要注入B對象,發(fā)現(xiàn)對象池里還沒有B對象。通過構(gòu)建函數(shù)創(chuàng)建B對象的實(shí)例化。又因B對象需要注入A對象,發(fā)現(xiàn)對象池里還沒有A對象,就會(huì)套娃。

【三級(jí)緩存】三級(jí)緩存實(shí)際上就是三個(gè)Map對象,從存放對象的順序開始

三級(jí)緩存singletonFactories存放ObjectFactory,傳入的是匿名內(nèi)部類,ObjectFactory.getObject() 方法最終會(huì)調(diào)用getEarlyBeanReference()進(jìn)行處理,返回創(chuàng)建bean實(shí)例化的lambda表達(dá)式。
二級(jí)緩存earlySingletonObjects存放bean,保存半成品bean實(shí)例,當(dāng)對象需要被AOP切面代時(shí),保存代理bean的實(shí)例beanProxy
一級(jí)緩存(單例池)singletonObjects存放完整的bean實(shí)例

/** 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);

二、三級(jí)緩存如何解決循環(huán)依賴?

【如何解決循環(huán)依賴】Spring解決循環(huán)依賴的核心思想在于提前曝光,首先創(chuàng)建實(shí)例化A,并在三級(jí)緩存singletonFactories中保存實(shí)例化A的lambda表達(dá)式以便獲取A實(shí)例,當(dāng)我沒有循環(huán)依賴和AOP時(shí),這個(gè)三級(jí)緩存singletonFactories是沒用在后續(xù)用到的。
但是當(dāng)我A對象需要注入B對象,發(fā)現(xiàn)緩存里還沒有B對象,創(chuàng)建B對象并又上述所說添加進(jìn)三級(jí)緩存singletonFactories,B對象需要注入A對象,這時(shí)從半成品緩存里取到半成品對象A,通過緩存的lambda表達(dá)式創(chuàng)建A實(shí)例對象,并放到二級(jí)緩存earlySingletonObjects中。
此時(shí)B對象可以注入A對象實(shí)例和初始化自己,之后將完成品B對象放入完成品緩存singletonObjects。但是當(dāng)有aop時(shí),B對象還沒有把完成品B對象放入完成品緩存singletonObjects中,B對象初始化后需要進(jìn)行代理對象的創(chuàng)建,此時(shí)需要從singletonFactories獲取bean實(shí)例對象,進(jìn)行createProxy創(chuàng)建代理類操作,這是會(huì)把proxy&B放入二級(jí)緩存earlySingletonObjects中。這時(shí)候才會(huì)把完整的B對象放入完成品一級(jí)緩存也叫單例池singletonObjects中,返回給A對象。
A對象繼續(xù)注入其他屬性和初始化,之后將完成品A對象放入完成品緩存。

三、使用二級(jí)緩存能不能解決循環(huán)依賴?

一定是不行,我們只保留二級(jí)緩存有兩個(gè)可能性保留一二singletonObjects和earlySingletonObjects,或者一三singletonObjects和singletonFactories

【只保留一二singletonObjects和earlySingletonObjects】

流程可以這樣走:實(shí)例化A ->將半成品的A放入earlySingletonObjects中 ->填充A的屬性時(shí)發(fā)現(xiàn)取不到B->實(shí)例化B->將半成品的B放入earlySingletonObjects中->從earlySingletonObjects中取出A填充B的屬性->將成品B放入singletonObjects,并從earlySingletonObjects中刪除B->將B填充到A的屬性中->將成品A放入singletonObjects并刪除earlySingletonObjects。

這樣的流程是線程安全的,不過如果A上加個(gè)切面(AOP),這種做法就沒法滿足需求了,因?yàn)閑arlySingletonObjects中存放的都是原始對象,而我們需要注入的其實(shí)是A的代理對象。

【只保留一三singletonObjects和singletonFactories】

流程是這樣的:實(shí)例化A ->創(chuàng)建A的對象工廠并放入singletonFactories中 ->填充A的屬性時(shí)發(fā)現(xiàn)取不到B->實(shí)例化B->創(chuàng)建B的對象工廠并放入singletonFactories中->從singletonFactories中獲取A的對象工廠并獲取A填充到B中->將成品B放入singletonObjects,并從singletonFactories中刪除B的對象工廠->將B填充到A的屬性中->將成品A放入singletonObjects并刪除A的對象工廠。

同樣,這樣的流程也適用于普通的IOC已經(jīng)有并發(fā)的場景,但如果A上加個(gè)切面(AOP)的話,這種情況也無法滿足需求。

因?yàn)槟玫絆bjectFactory對象后,調(diào)用ObjectFactory.getObject()方法最終會(huì)調(diào)用getEarlyBeanReference()方法,getEarlyBeanReference這個(gè)方法每次從三級(jí)緩存中拿到singleFactory對象,執(zhí)行g(shù)etObject()方法又會(huì)產(chǎn)生新的代理對象

所有這里我們要借助二級(jí)緩存來解決這個(gè)問題,將執(zhí)行了singleFactory.getObject()產(chǎn)生的對象放到二級(jí)緩存中去,后面去二級(jí)緩存中拿,沒必要再執(zhí)行一遍singletonFactory.getObject()方法再產(chǎn)生一個(gè)新的代理對象,保證始終只有一個(gè)代理對象。

getSingleton()、getEarlyBeanReference() 源碼如下

	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName); // 先從一級(jí)緩存拿
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName); // 拿二級(jí)緩存
				if (singletonObject == null && allowEarlyReference) {
                    // 拿三級(jí)緩存
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); 
					if (singletonFactory != null) {
                        // 最終會(huì)調(diào)用傳入的匿名內(nèi)部類getEarlyBeanReference()方法,這里面沒調(diào)用一次會(huì)生成一個(gè)新的代理對象
						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;
	}

到此這篇關(guān)于關(guān)于Java Spring三級(jí)緩存和循環(huán)依賴的深入理解的文章就介紹到這了,更多相關(guān)Java Spring 三級(jí)緩存 循環(huán)依賴內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 關(guān)于SpringMVC中控制器如何處理文件上傳的問題

    關(guān)于SpringMVC中控制器如何處理文件上傳的問題

    這篇文章主要介紹了關(guān)于SpringMVC中控制器如何處理文件上傳的問題,在 Web 應(yīng)用程序中,文件上傳是一個(gè)常見的需求,例如用戶上傳頭像、上傳文檔等,本文將介紹 Spring MVC 中的控制器如何處理文件上傳,并提供示例代碼,需要的朋友可以參考下
    2023-07-07
  • Java靜態(tài)代理和動(dòng)態(tài)代理詳解

    Java靜態(tài)代理和動(dòng)態(tài)代理詳解

    這篇文章主要介紹了Java靜態(tài)代理和動(dòng)態(tài)代理,本文通過代碼示例給大家講解的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-11-11
  • spring mvc中注解@ModelAttribute的妙用分享

    spring mvc中注解@ModelAttribute的妙用分享

    這篇文章主要給大家介紹了關(guān)于spring mvc中注解@ModelAttribute妙用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Android具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。
    2017-09-09
  • org.slf4j.Logger中info()方法的使用詳解

    org.slf4j.Logger中info()方法的使用詳解

    這篇文章主要介紹了org.slf4j.Logger中info()方法的使用詳解,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • 基于Feign傳輸對象無法接收參數(shù)的問題

    基于Feign傳輸對象無法接收參數(shù)的問題

    這篇文章主要介紹了基于Feign傳輸對象無法接收參數(shù)的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • 詳談Java中的Object、T(泛型)、?區(qū)別

    詳談Java中的Object、T(泛型)、?區(qū)別

    下面小編就為大家?guī)硪黄斦凧ava中的Object、T(泛型)、?區(qū)別。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • java字符串切割實(shí)例學(xué)習(xí)(獲取文件名)

    java字符串切割實(shí)例學(xué)習(xí)(獲取文件名)

    在Java中處理一些路徑相關(guān)的問題的時(shí)候,如要取出ie瀏覽器上傳文件的文件名,由于ie會(huì)把整個(gè)文件路徑都作為文件名上傳,需要用java.lang.String中的replaceAll或者split來處理,下面看看使用方法
    2013-12-12
  • Java微信公眾平臺(tái)開發(fā)(2) 微信服務(wù)器post消息體的接收

    Java微信公眾平臺(tái)開發(fā)(2) 微信服務(wù)器post消息體的接收

    這篇文章主要為大家詳細(xì)介紹了Java微信公眾平臺(tái)開發(fā)第二步,微信服務(wù)器post消息體的接收,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • Java OpenCV圖像處理之背景消除

    Java OpenCV圖像處理之背景消除

    GMM(高斯混合模型)是基于像素樣本統(tǒng)計(jì)信息的背景表示方法,利用像素在較長時(shí)間內(nèi)大量樣本值的概率密度等統(tǒng)計(jì)信息表示別境,然后使用統(tǒng)計(jì)差分進(jìn)行目標(biāo)像素判斷達(dá)到預(yù)期效果。本文將利用GMM方法實(shí)現(xiàn)圖像背景消除,需要的可以參考一下
    2022-02-02
  • Spring一步到位精通攔截器

    Spring一步到位精通攔截器

    攔截器(Interceptor)是一種動(dòng)態(tài)攔截方法調(diào)用的機(jī)制,在SpringMVC中動(dòng)態(tài)攔截控制器方法的執(zhí)行。本文將詳細(xì)講講SpringMVC中攔截器的概念及入門案例,感興趣的可以嘗試一下
    2023-01-01

最新評(píng)論