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

詳解Spring如何解決循環(huán)引用的問題

 更新時間:2023年08月13日 09:19:39   作者:隨機(jī)的未知  
在Spring框架中,當(dāng)兩個或多個Bean之間存在相互依賴關(guān)系時,可能會導(dǎo)致循環(huán)引用的問題,循環(huán)引用指的是兩個或多個Bean之間互相依賴,形成一個循環(huán)鏈,本文將和大家一起探討Spring如何解決循環(huán)引用的問題,感興趣的小伙伴跟著小編一起來看看吧

Spring如何解決循環(huán)引用的問題

關(guān)于循環(huán)引用,首先說一個結(jié)論:

Spring能夠解決的情況為:兩個對象都是單實(shí)例、且通過set方法進(jìn)行注入。

兩個對象都是單實(shí)例,通過構(gòu)造方法進(jìn)行注入,Spring不能進(jìn)行循環(huán)引用問題;

兩個對象都是多實(shí)例的情況下,不管是set注入,還是構(gòu)造注入,都不能解決Spring循環(huán)引用問題。

循環(huán)引用問題介紹

循環(huán)引用問題即:

有A,B兩個類,A類中有B類型的成員變量b、B類中有A類型的成員變量a。創(chuàng)建a的過程需要b,創(chuàng)建b的過程又需要a;

循環(huán)引用問題演示

循環(huán)引用問題分析

請看如下流程:

  1. 調(diào)用getBean("a")來獲取a對象;
  2. 先調(diào)用getSingleton("a")來嘗試獲取a,但是獲取不到;
  3. 需要調(diào)用doCreateBean()來創(chuàng)建a;
  4. a的b屬性是null,需要填充b屬性;
  5. 調(diào)用getBean("b")來獲取b對象;
  6. 先調(diào)用getSingleton("b")來嘗試獲取b,但是獲取不到;
  7. 需要調(diào)用doCreateBean()來創(chuàng)建b;
  8. b的a屬性是null,需要填充a屬性;
  9. 又需要要調(diào)用getBean("a")來獲取a。

這時getBean("a")可以獲取到嗎?如果能獲取到,是在哪里獲取的?如果獲取不到,又會有什么問題呢?

我們首先看下getSingleton()源碼:

image-20230809203549677

addSingleton方法如下圖:

addSingleton

如此可以看到,在進(jìn)行實(shí)例化、屬性填充、初始化都完成后才會放到singletonObjects中。

那getSingleton()方法就獲取不到a,只能再去創(chuàng)建a對象了嗎?當(dāng)然不是,如果再去創(chuàng)建a,a就不是單例的呢。

所以這就需要**沒有創(chuàng)建完全的a也要存儲起來。**但是并沒有存儲到singletonObjects中,因?yàn)閟ingletonObjects是存儲例化、屬性填充、初始化都完成后的對象。

Spring又為我們定義了兩個存儲的位置:earlySingletonObjects、singletonFactories。

那什么時候?qū)⑽磩?chuàng)建完全的對象存儲起來呢?

這我們應(yīng)該在實(shí)例化對象完成后,填充屬性前的代碼查找??梢钥吹饺缦麓a:

doCreateBean

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
addSingletonFactory方法源碼如下:
protected void addSingletonFactory(String beanName, ObjectFactory <? > singletonFactory) {
    Assert.notNull(singletonFactory, "Singleton factory must not be null");
    synchronized(this.singletonObjects) {
        if(!this.singletonObjects.containsKey(beanName)) {
            this.singletonFactories.put(beanName, singletonFactory);
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.add(beanName);
        }
    }
}

實(shí)例化后,會把創(chuàng)建非完全體對象的工廠放到singletonFactories里,這個工廠就是lambda表達(dá)式() -> getEarlyBeanReference(beanName, mbd, bean)調(diào)用的getEarlyBeanReference(beanName, mbd, bean)方法。

getEarlyBeanReference

addSingletonFactory還會把earlySingletonObjects、registeredSingletons中的對象刪除。

singletonFactories 存儲:不完全體的bean的id作為key,一個工廠作為value; 工廠方法是lambda表達(dá)式()->getEarlyBeanReference(beanName, mbd, bean) 此方法內(nèi)部使用了BeanPostProcessor。

singletonFactories為什么不存儲未完全體的a,而存儲一個工廠方法呢?

這意味著他會處理一些復(fù)雜功能。

最簡單的循環(huán)引用的問題

上述介紹的循環(huán)引用的問題,是最簡單的情況。還有一些復(fù)雜情況。

如果A需要做AOP,需要為A做代理呢?或者B也要做代理呢?

復(fù)雜情況的循環(huán)引用

代理是在初始化階段使用BeanPostProcessor的postProcessAfterInitialization()方法來做的。

singletonFactories存工廠的原因

singletonFactories存工廠的原因:

為b填充屬性a時,需要獲取到不完全體的a,為b賦值; 并且如果A需要做代理; 而代理是在BeanPostProcessor中的postProcessAfterInitialization()方法做的; 所以singletonFactories存儲的是一個工廠(里面的方法是用BeanPostProcessor中的); 這樣就無需在a初始化的過程中創(chuàng)建代理了,可以把a(bǔ)的代理提前創(chuàng)建出來。

那在A創(chuàng)建過程中是否還要創(chuàng)建代理呢?————不會。

在上面提前創(chuàng)建a的代理完成后,會將代理對象放到代理緩存中,在a初始化創(chuàng)建代理時,直接從代理緩存中拿就可以了。

站在b的角度講,現(xiàn)在b的屬性填充完成了,后面就是初始化了,在初始化過程中,就可以走正常的代理過程了。

a在填充屬性時,就可以填充b的代理了,就可以走初始化了,初始化過程中的代理從代理緩存獲取就可以了。

為b填充a代理對象分析

doGetBean()中的getSingleton方法:

getSingleton

getSingleton重載1

getSingleton重載2

在為b填充a的代理時,singletonFactory.getObject()就會回調(diào)存儲起來的那個lambda表達(dá)式()->getEarlyBeanReference(beanName, mbd, bean)。

核心代碼

會把a(bǔ)的代理獲取出來;

然后把a(bǔ)的代理放到earlySingletonObjects中;

把存儲的a工廠的lambda表達(dá)式從singletonFactories中移除。

b初始化完成后,b就是完全體了,調(diào)用addSingleton()方法就會把b存儲到singletonObjects中了。

等a再初始化完成就是完全體了。

這樣就解決了循環(huán)引用問題。

以上就是詳解Spring如何解決循環(huán)引用的問題的詳細(xì)內(nèi)容,更多關(guān)于Spring循環(huán)引用的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java was started but returned exit code=13問題解決案例詳解

    Java was started but returned exit code=13問題解決案例詳解

    這篇文章主要介紹了Java was started but returned exit code=13問題解決案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • 通過Java實(shí)現(xiàn)RSA加密與驗(yàn)證的方法詳解

    通過Java實(shí)現(xiàn)RSA加密與驗(yàn)證的方法詳解

    RSA是一種非對稱加密算法,是目前廣泛應(yīng)用于加密和數(shù)字簽名領(lǐng)域的一種加密算法,本文主要講述如何通過Java實(shí)現(xiàn)RSA加密與驗(yàn)證,應(yīng)用場景為與其他平臺對接接口時,通過RSA加密和解密驗(yàn)證請求的有效性,在對接時雙方互換公鑰,需要的朋友可以參考下
    2023-12-12
  • SpringMVC實(shí)現(xiàn)數(shù)據(jù)綁定及表單標(biāo)簽

    SpringMVC實(shí)現(xiàn)數(shù)據(jù)綁定及表單標(biāo)簽

    這篇文章主要為大家詳細(xì)介紹了SpringMVC實(shí)現(xiàn)數(shù)據(jù)綁定及表單標(biāo)簽的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • Java實(shí)現(xiàn)文字滾動廣告字幕效果

    Java實(shí)現(xiàn)文字滾動廣告字幕效果

    文字滾動廣告字幕是一種常見的動態(tài)文本展示效果,通常用于展示新聞、廣告或其他動態(tài)信息,在本項(xiàng)目中,我們將使用Java的Swing庫來實(shí)現(xiàn)一個簡單的文字滾動廣告字幕效果,通過定時更新文本的位置來模擬文字的滾動,需要的朋友可以參考下
    2025-02-02
  • Java編程簡單應(yīng)用

    Java編程簡單應(yīng)用

    本文主要介紹了三個簡單Java小程序———1、HelloWorld(HelloWorld的來源);2、輸出個人信息3、輸出特殊圖案。具有很好的參考價值,下面跟著小編一起來看下吧
    2017-02-02
  • idea中導(dǎo)入別人的springboot項(xiàng)目的方法(圖文)

    idea中導(dǎo)入別人的springboot項(xiàng)目的方法(圖文)

    這篇文章主要介紹了idea中導(dǎo)入別人的springboot項(xiàng)目的方法(圖文),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Web容器啟動過程中如何執(zhí)行Java類

    Web容器啟動過程中如何執(zhí)行Java類

    這篇文章主要介紹了Web容器啟動過程中如何執(zhí)行Java類,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-10-10
  • springMVC圖片上傳的處理方式詳解

    springMVC圖片上傳的處理方式詳解

    這篇文章主要為大家詳細(xì)介紹了springMVC圖片上傳的處理方式,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • java利用JEXL實(shí)現(xiàn)動態(tài)表達(dá)式編譯

    java利用JEXL實(shí)現(xiàn)動態(tài)表達(dá)式編譯

    這篇文章主要介紹了java利用JEXL實(shí)現(xiàn)動態(tài)表達(dá)式編譯,系統(tǒng)要獲取多個數(shù)據(jù)源的數(shù)據(jù),并進(jìn)行處理,最后輸出多個字段。字段的計(jì)算規(guī)則一般是簡單的取值最多加一點(diǎn)條件判斷,下面是具體的實(shí)現(xiàn)方法
    2021-04-04
  • 淺談JSON的數(shù)據(jù)交換、緩存問題和同步問題

    淺談JSON的數(shù)據(jù)交換、緩存問題和同步問題

    這篇文章主要介紹了淺談JSON的數(shù)據(jù)交換、緩存問題和同步問題,具有一定借鑒價值,需要的朋友可以參考下
    2017-12-12

最新評論