真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Spring循環(huán)依賴的原理是什么

這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)碛嘘P(guān)Spring循環(huán)依賴的原理是什么,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

成都創(chuàng)新互聯(lián)公司是專業(yè)的橋東網(wǎng)站建設(shè)公司,橋東接單;提供成都網(wǎng)站制作、成都做網(wǎng)站,網(wǎng)頁設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行橋東網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來合作!

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

Spring循環(huán)依賴的原理是什么

從字面上來理解就是A依賴B的同時(shí)B也依賴了A,就像上面這樣,或者C依賴與自己本身。體現(xiàn)到代碼層次就是這個(gè)樣子

@Componentpublic class A {
 // A中注入了B @Autowired private B b;
}
---@Componentpublic class A {
 // A中注入了B @Autowired private B b;
}
---// 自己依賴自己@Componentpublic class C {
 // C中注入了C @Autowired private C c;
}

雖然體現(xiàn)形式不一樣,但是實(shí)際上都是循環(huán)依賴的問題。

什么情況下循環(huán)依賴可以被處理?

Spring解決循環(huán)依賴是有前置條件

  • 出現(xiàn)循環(huán)依賴的Bean必須要是單例(singleton),如果依賴prototype則完全不會(huì)有此需求。

  • 依賴注入的方式不能全是構(gòu)造器注入的方式(只能解決setter方法的循環(huán)依賴,這是錯(cuò)誤的)

1. AB 均采用setter方法注入 結(jié)果OK

Spring循環(huán)依賴的原理是什么

2. AB 均采用屬性Autowired注入 結(jié)果ok

Spring循環(huán)依賴的原理是什么

3. AB均采用構(gòu)造器方法注入 出現(xiàn)循環(huán)依賴

Spring循環(huán)依賴的原理是什么

4. A中注入B的方式為setter方法,B中注入A的方式為構(gòu)造器

Spring循環(huán)依賴的原理是什么

5. A中注入B的方式為構(gòu)造器,B中注入A的方式為setter方法。

Spring循環(huán)依賴的原理是什么

結(jié)論

依賴情況依賴注入方式是否解決
AB相互依賴(循環(huán)依賴)均采用setter方法注入
AB相互依賴(循環(huán)依賴)均采用屬性自動(dòng)注入
AB相互依賴(循環(huán)依賴)均采用構(gòu)造器注入
AB相互依賴(循環(huán)依賴)A中注入B的方式為setter方法,B中注入A的方式為構(gòu)造器
AB相互依賴(循環(huán)依賴)B中注入A的方式為setter方法,A中注入B的方式為構(gòu)造器,Spring在創(chuàng)建Bean時(shí)默認(rèn)會(huì)根據(jù)自然排序進(jìn)行創(chuàng)建,A會(huì)先于B進(jìn)行創(chuàng)建

從上面的測(cè)試結(jié)果我們可以看到,不是只有在setter方法注入的情況下循環(huán)依賴才能被解決,即使存在構(gòu)造器注入的場(chǎng)景下,循環(huán)依賴依然被可以被正常處理掉。

Spring循環(huán)依賴的通俗說

Spring bean 的創(chuàng)建,其本質(zhì)上還是一個(gè)對(duì)象的創(chuàng)建,既然是對(duì)象,一定要明白一點(diǎn)就是,一個(gè)完整的對(duì)象包含兩部分:當(dāng)前對(duì)象實(shí)例化和對(duì)象屬性的實(shí)例化。在Spring中,對(duì)象的實(shí)例化是通過反射實(shí)現(xiàn)的,而對(duì)象的屬性則是在對(duì)象實(shí)例化之后通過一定的方式設(shè)置的。這個(gè)過程可以按照如下方式進(jìn)行理解:Spring循環(huán)依賴的原理是什么

Spring循環(huán)依賴的原理是什么

大致繪制依賴流程圖如下:Spring循環(huán)依賴的原理是什么

Spring循環(huán)依賴的原理是什么

圖中g(shù)etBean()表示調(diào)用Spring的ApplicationContext.getBean()方法,而該方法中的參數(shù),則表示我們要嘗試獲取的目標(biāo)對(duì)象。圖中的黑色箭頭表示一開始的方法調(diào)用走向,走到最后,返回了Spring中緩存的A對(duì)象之后,表示遞歸調(diào)用返回了,此時(shí)使用綠色箭頭表示。從圖中我們可以很清楚的看到,B對(duì)象的a屬性是在第三步中注入的半成品A對(duì)象,而A對(duì)象的b屬性是在第二步中注入的成品B對(duì)象,此時(shí)半成品的A對(duì)象也就變成了成品的A對(duì)象,因?yàn)槠鋵傩砸呀?jīng)設(shè)置完成了。

到這里,Spring整個(gè)解決循環(huán)依賴問題的實(shí)現(xiàn)思路已經(jīng)比較清楚了。對(duì)于整體過程只要理解兩點(diǎn):

  • Spring是通過遞歸的方式獲取目標(biāo)bean及其所依賴的bean的;

  • Spring實(shí)例化一個(gè)bean的時(shí)候,是分兩步進(jìn)行的,首先實(shí)例化目標(biāo)bean,然后為其注入屬性。

結(jié)合這兩點(diǎn),也就是說,Spring在實(shí)例化一個(gè)bean的時(shí)候,是首先遞歸的實(shí)例化其所依賴的所有bean,直到某個(gè)bean沒有依賴其他bean,此時(shí)就會(huì)將該實(shí)例返回,然后反遞歸的將獲取到的bean設(shè)置為各個(gè)上層bean的屬性的

Spring循環(huán)依賴進(jìn)階

一個(gè)對(duì)象一般創(chuàng)建過程有3部分組成:

  1. 實(shí)例化:簡(jiǎn)單理解就是new了一個(gè)對(duì)象

  2. 屬性注入:為實(shí)例化中new出來的對(duì)象填充屬性

  3. 初始化:執(zhí)行aware接口中的方法,初始化方法,完成AOP代理

Spring是通過「三級(jí)緩存」來解決上述問題的:

  • singletonObjects:一級(jí)緩存 存儲(chǔ)的是所有創(chuàng)建好了的單例Bean

  • earlySingletonObjects:完成實(shí)例化,但是還未進(jìn)行屬性注入及初始化的對(duì)象

  • singletonFactories:提前暴露的一個(gè)單例工廠,二級(jí)緩存中存儲(chǔ)的就是從這個(gè)工廠中獲取到的對(duì)象

然后接下來說下普通循環(huán)依賴跟帶AOP的循環(huán)依賴。

普通循環(huán)依賴圖

Spring循環(huán)依賴的原理是什么

結(jié)論:沒有進(jìn)行AOP的Bean間的循環(huán)依賴 從上圖分析可以看出,這種情況下「三級(jí)緩存根本沒用」!所以不會(huì)存在什么提高了效率的說法

帶AOP循環(huán)依賴

帶AOP的跟不帶AOP的其實(shí)幾乎一樣,只是在三級(jí)緩存中存放的是函數(shù)式接口,在需要調(diào)用時(shí)直接返回代理對(duì)象。三級(jí)緩存存在的意義:

?

只有真正發(fā)生循環(huán)依賴的時(shí)候,才去提前生成代理對(duì)象,否則只會(huì)創(chuàng)建一個(gè)工廠并將其放入到三級(jí)緩存中,但是不會(huì)去通過這個(gè)工廠去真正創(chuàng)建對(duì)象

?

Spring循環(huán)依賴的原理是什么


是否可以用二級(jí)緩存而不用三級(jí)緩存?

?

答案:不可以,違背Spring在結(jié)合AOP跟Bean的生命周期的設(shè)計(jì)!Spring結(jié)合AOP跟Bean的生命周期(看下圖)本身就是通過AnnotationAwareAspectJAutoProxyCreator這個(gè)后置處理器來完成的,在這個(gè)后置處理的postProcessAfterInitialization方法中對(duì)初始化后的Bean完成AOP代理。如果出現(xiàn)了循環(huán)依賴,那沒有辦法,只有給Bean先創(chuàng)建代理,但是沒有出現(xiàn)循環(huán)依賴的情況下,設(shè)計(jì)之初就是讓Bean在生命周期的「最后一步完成代理而不是在實(shí)例化后就立馬完成代理」。

?

Spring循環(huán)依賴的原理是什么

使用了三級(jí)緩存的情況下,A、B的創(chuàng)建流程Spring循環(huán)依賴的原理是什么

不使用三級(jí)緩存,直接在二級(jí)緩存中Spring循環(huán)依賴的原理是什么

結(jié)論:上面兩個(gè)流程的唯一區(qū)別在于為A對(duì)象創(chuàng)建代理的時(shí)機(jī)不同,使用三級(jí)緩存的情況下為A創(chuàng)建代理的時(shí)機(jī)是在B中需要注入A的時(shí)候,而不使用三級(jí)緩存的話在A實(shí)例化后就需要馬上為A創(chuàng)建代理然后放入到二級(jí)緩存中去。三級(jí)緩存是無法提速的!

回答模板

Spring如何解決循環(huán)依賴的

答:Spring通過三級(jí)緩存解決了循環(huán)依賴,其中一級(jí)緩存為單例池(singletonObjects),二級(jí)緩存為早期曝光對(duì)象earlySingletonObjects,三級(jí)緩存為早期曝光對(duì)象工廠(singletonFactories)。

當(dāng)A、B兩個(gè)類發(fā)生循環(huán)引用時(shí),在A完成實(shí)例化后,就使用實(shí)例化后的對(duì)象去創(chuàng)建一個(gè)對(duì)象工廠,添加到三級(jí)緩存中,如果A被AOP代理,那么通過這個(gè)工廠獲取到的就是A代理后的對(duì)象,如果A沒有被AOP代理,那么這個(gè)工廠獲取到的就是A實(shí)例化的對(duì)象。

當(dāng)A進(jìn)行屬性注入時(shí),會(huì)去創(chuàng)建B,同時(shí)B又依賴了A,所以創(chuàng)建B的同時(shí)又會(huì)去調(diào)用getBean(a)來獲取需要的依賴,此時(shí)的getBean(a)會(huì)從緩存中獲取:

?

第一步:先獲取到三級(jí)緩存中的工廠;

第二步:調(diào)用對(duì)象工工廠的getObject方法來獲取到對(duì)應(yīng)的對(duì)象,得到這個(gè)對(duì)象后將其注入到B中。緊接著B會(huì)走完它的生命周期流程,包括初始化、后置處理器等。

第三步:當(dāng)B創(chuàng)建完后,會(huì)將B再注入到A中,此時(shí)A再完成它的整個(gè)生命周期。至此,循環(huán)依賴結(jié)束!

?

面試官:為什么要使用三級(jí)緩存呢?二級(jí)緩存能解決循環(huán)依賴嗎?

?

答:如果要使用二級(jí)緩存解決循環(huán)依賴,意味著所有Bean在實(shí)例化后就要完成AOP代理,這樣違背了Spring設(shè)計(jì)的原則,Spring在設(shè)計(jì)之初就是通過AnnotationAwareAspectJAutoProxyCreator這個(gè)后置處理器來在Bean生命周期的最后一步來完成AOP代理,而不是在實(shí)例化后就立馬進(jìn)行AOP代理。

?

跟蹤核心大致流程

Spring循環(huán)依賴的原理是什么

上述就是小編為大家分享的Spring循環(huán)依賴的原理是什么了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。


網(wǎng)頁名稱:Spring循環(huán)依賴的原理是什么
URL鏈接:http://weahome.cn/article/jiejss.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部