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