Spring 對于循環(huán)依賴的處理


什么是循環(huán)依賴

循環(huán)依賴就是循環(huán)引用,就是兩個或者多個bean相互之間的持有對方。

循環(huán)依賴的類型

  • 構(gòu)造器循環(huán)依賴
  • setter循環(huán)依賴

我們先來看看如下的例子:

public class First {
    private  Second second;

    public void a () {
        second.b();
    }

    public Second getSecond() {
        return second;
    }
    public void setSecond(Second second) {
        this.second = second;
    }
}

public class Second {
    private Third third;

    public void b() {
        third.c();
    }

    public Third getThird() {
        return this.third;
    }

    public void setThird(Third third) {
        this.third = third;
    }
}

public class Third {
    private First first;

    public void c() {
        first.a();
    }

    public void setFirst(First first) {
        this.first = first;
    }

    public First getFirst() {
        return this.first;
    }
}

我們先來看看上面例子的兩種循環(huán)依賴的情況。

構(gòu)造器循環(huán)依賴

我們Bean的初始化是方式可以通過如下的xml過程.

<bean id="first">
  <constructor-arg index="0" ref="second"/>
</bean>
<bean id="second">
  <constructor-arg index="0" ref="third"/>
</bean>
<bean id="third">
  <constructor-arg index="0" ref="first"/>
</bean>

Spring容器將每一個正在創(chuàng)建的bean標(biāo)識符放在一個“當(dāng)前正在創(chuàng)建bean的池”中,bean標(biāo)識符在創(chuàng)建的過程中將一直保持在這個池中,因此,如果在創(chuàng)建bean過程中發(fā)現(xiàn)自己已經(jīng)在這個池中,將會拋出'BeanCurrentlyInCreationException'異常標(biāo)識循環(huán)依賴無法處理;而對于創(chuàng)建完畢的bean將會從池中清除。
針對上述的這個例子,我們來理一下這個過程:

  1. Spring 容器創(chuàng)建"first"bean,首先會去池中查找是否已經(jīng)創(chuàng)建當(dāng)前的“first”bean,如果沒有發(fā)現(xiàn),進行調(diào)用構(gòu)造器創(chuàng)建,這個時候,構(gòu)造器需要參數(shù)second進行創(chuàng)建,因此,就要進行一個創(chuàng)建second的bean,同時,由于當(dāng)前first是剛好處于一個正在創(chuàng)建的過程中,所以,我們要將first放入到我們這個“當(dāng)前正在創(chuàng)建bean的池”中。
  2. 由第一步的構(gòu)造器依賴,我們要接著創(chuàng)建second的bean,過程和first的一樣,先進行一個判斷是否存在second在池中,沒有的話,就進行構(gòu)造器創(chuàng)建,有依賴參數(shù),就依賴參數(shù)的bean的創(chuàng)建,同時,將second放入池中。
  3. 同樣的和上述的過程一樣,但是,在這個時候,我們要進行構(gòu)造器創(chuàng)建bean的時候,需要依賴first,那么我們按照上面的邏輯不走往下走的過程應(yīng)該就是去創(chuàng)建first,那這個時候,這一步就回到了第一步的動作。但是,在第一步的時候,我們還是要進行一個檢查判斷是否在池中已經(jīng)存在first。顯然,這個時候,池中已經(jīng)存在了我們剛剛創(chuàng)建的first的bean,因此,就會拋出BeanCurrentlyInCreationException這個異常了。

所以,我們從上面的過程可以得出一個結(jié)論,構(gòu)造器的循環(huán)依賴是沒法解決。

setter循環(huán)依賴

對于setter注入造成的循環(huán)依賴是通過Spring容器提前暴露完成構(gòu)造器注入,但是未完成其他步驟(如,setter注入)的bean來完成的。簡單的說就是,先調(diào)用一個無參構(gòu)造函數(shù),進行一個創(chuàng)建bean的實例,然后在創(chuàng)建完這個實例之后, 在調(diào)用相應(yīng)的setter方法,將依賴填充進去。
對于上述例子,我們使用setter循環(huán)依賴的過程是這樣的:

  1. Spring 容器創(chuàng)建單例"first"bean,首先根據(jù)無參構(gòu)造器創(chuàng)建bean first,并暴露一個"ObjectFactory"用于返回一個提前暴露一個創(chuàng)建中的bean,并將first標(biāo)識放入“當(dāng)前正在創(chuàng)建bean的池”中,然后進行setter注入second。
  2. 創(chuàng)建bean second 和第一步同樣的動作,然后進行setter注入third。
  3. 創(chuàng)建bean third和前面的步驟都一樣,但是在進行setter注入first的時候,由于提前暴露了ObjectFactory工廠,從而使它能夠返回提前創(chuàng)建中的一個bean。
  4. 最后在完成對third,second的setter注入。

所以,通過setter注入,是能夠解決循環(huán)依賴的問題。


Spring對Bean的創(chuàng)建

通過上述的構(gòu)造器循環(huán)依賴的創(chuàng)建bean和setter循環(huán)依賴的創(chuàng)建bean,我們可以發(fā)現(xiàn),spring在處理的時候,走的是兩種不同的方式進行一個處理。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容