摘要:如下圖注意,這里不是函數(shù)的循環(huán)調(diào)用,是對象的相互依賴關系。因此如果在創(chuàng)建過程中發(fā)現(xiàn)自己已經(jīng)在當前創(chuàng)建池里時將拋出異常表示循環(huán)依賴而對于創(chuàng)建完畢的將從當前創(chuàng)建池中清除掉。
什么是循環(huán)依賴?
循環(huán)依賴其實就是循環(huán)引用,也就是兩個或則兩個以上的bean互相持有對方,最終形成閉環(huán)。比如A依賴于B,B依賴于C,C又依賴于A。如下圖:
注意,這里不是函數(shù)的循環(huán)調(diào)用,是對象的相互依賴關系。循環(huán)調(diào)用其實就是一個死循環(huán),除非有終結(jié)條件。
Spring中循環(huán)依賴場景有:
構造器的循環(huán)依賴
setter方式單例,默認方式
setter方式原型,prototype
第一種:構造器參數(shù)循環(huán)依賴
Spring容器會將每一個正在創(chuàng)建的Bean 標識符放在一個“當前創(chuàng)建Bean池”中,Bean標識符在創(chuàng)建過程中將一直保持在這個池中。
因此如果在創(chuàng)建Bean過程中發(fā)現(xiàn)自己已經(jīng)在“當前創(chuàng)建Bean池”里時將拋出BeanCurrentlyInCreationException異常表示循環(huán)依賴;而對于創(chuàng)建完畢的Bean將從“當前創(chuàng)建Bean池”中清除掉。
首先我們先初始化三個Bean。
OK,上面是很基本的3個類,,StudentA有參構造是StudentB。StudentB的有參構造是StudentC,StudentC的有參構造是StudentA ,這樣就產(chǎn)生了一個循環(huán)依賴的情況,
我們都把這三個Bean交給Spring管理,并用有參構造實例化。
下面是測試類:
publicclassTest{
publicstaticvoidmain(String[] args){
ApplicationContext context =newClassPathXmlApplicationContext("com/zfx/student/applicationContext.xml");
//System.out.println(context.getBean("a", StudentA.class));
}
}
執(zhí)行結(jié)果報錯信息為:
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating beanwithname"a": Requested beaniscurrentlyincreation:Isthere an unresolvable circular reference?
如果大家理解開頭那句話的話,這個報錯應該不驚訝,Spring容器先創(chuàng)建單例StudentA,StudentA依賴StudentB,然后將A放在“當前創(chuàng)建Bean池”中,此時創(chuàng)建StudentB,StudentB依賴StudentC ,然后將B放在“當前創(chuàng)建Bean池”中,此時創(chuàng)建StudentC,StudentC又依賴StudentA, 但是,此時Student已經(jīng)在池中,所以會報錯,,因為在池中的Bean都是未初始化完的,所以會依賴錯誤 ,(初始化完的Bean會從池中移除)
第二種:setter方式單例,默認方式
如果要說setter方式注入的話,我們最好先看一張Spring中Bean實例化的圖
如圖中前兩步驟得知:Spring是先將Bean對象實例化之后再設置對象屬性的
修改配置文件為set方式注入
下面是測試類:
publicclassTest{
publicstaticvoidmain(String[] args){
ApplicationContext context =newClassPathXmlApplicationContext("com/zfx/student/applicationContext.xml");
System.out.println(context.getBean("a", StudentA.class));
}
}
打印結(jié)果為:
com.zfx.student.StudentA@1fbfd6
為什么用set方式就不報錯了呢 ?
我們結(jié)合上面那張圖看, Spring先是用構造實例化 Bean對象 ,此時Spring會將這個實例化結(jié)束的對象放到一個Map中,并且Spring提供了獲取這個未設置屬性的實例化對象引用的方法。
結(jié)合我們的實例來看,,當Spring實例化了StudentA、StudentB、StudentC后,緊接著會去設置對象的屬性,此時StudentA依賴StudentB,就會去Map中取出存在里面的單例StudentB對象,以此類推,不會出來循環(huán)的問題嘍、
下面是Spring源碼中的實現(xiàn)方法。以下的源碼在Spring的Bean包中的DefaultSingletonBeanRegistry.java類中
第三種:setter方式原型,prototype
修改配置文件為:
測試用例:
publicclassTest{
publicstaticvoidmain(String[] args){
ApplicationContext context =newClassPathXmlApplicationContext("com/zfx/student/applicationContext.xml");
//此時必須要獲取Spring管理的實例,因為現(xiàn)在scope="prototype" 只有請求獲取的時候才會實例化對象
System.out.println(context.getBean("a", StudentA.class));
}
}
打印結(jié)果:
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating beanwithname"a": Requested beaniscurrentlyincreation:Isthere an unresolvable circular reference?
為什么原型模式就報錯了呢 ?
對于“prototype”作用域Bean,Spring容器無法完成依賴注入,因為“prototype”作用域的Bean,Spring容器不進行緩存,因此無法提前暴露一個創(chuàng)建中的Bean。
感謝您耐心看完的文章
順便給大家推薦一個Java技術交流群:710373545里面會分享一些資深架構師錄制的視頻資料:有Spring,MyBatis,Netty源碼分析,高并發(fā)、高性能、分布式、微服務架構的原理,JVM性能優(yōu)化、分布式架構等這些成為架構師必備的知識體系。還能領取免費的學習資源,目前受益良多!
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/74638.html
摘要:當普通對象要轉(zhuǎn)換成時就很有用,因為返回的格式與構造函數(shù)接受的格式完全相同。使用常規(guī)的構造函數(shù)可以將一個二維鍵值對數(shù)組轉(zhuǎn)換成一個對象。在和早期標準中,根本沒有指定屬性的順序。此函數(shù)還可以輕松地將純對象屬性映射到對象中。 為了保證的可讀性,本文采用意譯而非直譯。 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! 自身可枚舉屬性 Object.keys() 方法會返回一個...
摘要:雖然和都可以獲取組件實例,但是它們無法在跨級或兄弟間通信,這是它們的缺點。也就是在父組件中提供一個值,并且在需要使用的子孫組件中注入改值,即不僅僅是,只要是的子組件,無論隔多少代,都可以通過這個的方式注入。通過混入組件,實現(xiàn)組件間的通信。 寫在前面 vue 的組件化應該是其最核心的思想了,無論是一個大的頁面還是一個小的按鈕,都可以被稱之為組件。基于 Vue 的開發(fā),就是在寫一個個組件,...
摘要:本教程解釋了現(xiàn)代中各種各樣的循環(huán)可能性目錄介紹提供了許多迭代循環(huán)的方法。引入了循環(huán),它結(jié)合了的簡潔性和破解能力注意使用。此循環(huán)在每次迭代中創(chuàng)建一個新范圍,因此我們可以安全地使用它而不是。 JavaScript提供了許多通過LOOPS迭代的方法。本教程解釋了現(xiàn)代JAVASCRIPT中各種各樣的循環(huán)可能性 showImg(https://segmentfault.com/img/bVbfH...
摘要:本教程解釋了現(xiàn)代中各種各樣的循環(huán)可能性目錄介紹提供了許多迭代循環(huán)的方法。引入了循環(huán),它結(jié)合了的簡潔性和破解能力注意使用。此循環(huán)在每次迭代中創(chuàng)建一個新范圍,因此我們可以安全地使用它而不是。 JavaScript提供了許多通過LOOPS迭代的方法。本教程解釋了現(xiàn)代JAVASCRIPT中各種各樣的循環(huán)可能性 showImg(https://segmentfault.com/img/bVbfH...
摘要:本教程解釋了現(xiàn)代中各種各樣的循環(huán)可能性目錄介紹提供了許多迭代循環(huán)的方法。引入了循環(huán),它結(jié)合了的簡潔性和破解能力注意使用。此循環(huán)在每次迭代中創(chuàng)建一個新范圍,因此我們可以安全地使用它而不是。 JavaScript提供了許多通過LOOPS迭代的方法。本教程解釋了現(xiàn)代JAVASCRIPT中各種各樣的循環(huán)可能性 showImg(https://segmentfault.com/img/bVbfH...
閱讀 3690·2021-09-07 10:19
閱讀 3633·2021-09-03 10:42
閱讀 3588·2021-09-03 10:28
閱讀 2555·2019-08-29 14:11
閱讀 814·2019-08-29 13:54
閱讀 1600·2019-08-29 12:14
閱讀 421·2019-08-26 12:12
閱讀 3619·2019-08-26 10:45