黄色网页视频 I 影音先锋日日狠狠久久 I 秋霞午夜毛片 I 秋霞一二三区 I 国产成人片无码视频 I 国产 精品 自在自线 I av免费观看网站 I 日本精品久久久久中文字幕5 I 91看视频 I 看全色黄大色黄女片18 I 精品不卡一区 I 亚洲最新精品 I 欧美 激情 在线 I 人妻少妇精品久久 I 国产99视频精品免费专区 I 欧美影院 I 欧美精品在欧美一区二区少妇 I av大片网站 I 国产精品黄色片 I 888久久 I 狠狠干最新 I 看看黄色一级片 I 黄色精品久久 I 三级av在线 I 69色综合 I 国产日韩欧美91 I 亚洲精品偷拍 I 激情小说亚洲图片 I 久久国产视频精品 I 国产综合精品一区二区三区 I 色婷婷国产 I 最新成人av在线 I 国产私拍精品 I 日韩成人影音 I 日日夜夜天天综合

【第三章】 DI 之 3.2 循環依賴 ——跟我學spri

系統 2073 0

?

3.2.1? 什么是循環依賴

?????? 循環依賴就是循環引用,就是兩個或多個Bean相互之間的持有對方,比如CircleA引用CircleB,CircleB引用CircleC,CircleC引用CircleA,則它們最終反映為一個環。此處不是循環調用,循環調用是方法之間的環調用。如圖3-5所示:

? 【第三章】 DI 之 3.2 循環依賴 ——跟我學spring3

圖3-5 循環引用

?????? 循環調用是無法解決的,除非有終結條件,否則就是死循環,最終導致內存溢出錯誤。

?????? Spring容器循環依賴包括構造器循環依賴和setter循環依賴,那Spring容器如何解決循環依賴呢?首先讓我們來定義循環引用類:

?

java代碼:
  1. package ?cn.javass.spring.chapter3.bean;??
  2. public ? class ?CircleA?{??
  3. ???? private ?CircleB?circleB;??
  4. ???? public ?CircleA()?{??
  5. ????}??
  6. ???? public ?CircleA(CircleB?circleB)?{??
  7. ???????? this .circleB?=?circleB;??
  8. ????}??
  9. public ? void ?setCircleB(CircleB?circleB)???
  10. {??
  11. ???????? this .circleB?=?circleB;??
  12. ????}??
  13. public ? void ?a()?{??
  14. ???circleB.b();??
  15. }??
  16. }??

?

java代碼:
  1. package ?cn.javass.spring.chapter3.bean;??
  2. public ? class ?CircleB?{??
  3. ???? private ?CircleC?circleC;??
  4. ???? public ?CircleB()?{??
  5. ????}??
  6. ???? public ?CircleB(CircleC?circleC)?{??
  7. ???????? this .circleC?=?circleC;??
  8. ????}??
  9. public ? void ?setCircleC(CircleC?circleC)???
  10. {??
  11. ???????? this .circleC?=?circleC;??
  12. ????}??
  13. ???? public ? void ?b()?{??
  14. ????????circleC.c();??
  15. ????}??
  16. }??

?

java代碼:
  1. package ?cn.javass.spring.chapter3.bean;??
  2. public ? class ?CircleC?{??
  3. ???? private ?CircleA?circleA;??
  4. ???? public ?CircleC()?{??
  5. ????}??
  6. ???? public ?CircleC(CircleA?circleA)?{??
  7. ???????? this .circleA?=?circleA;??
  8. ????}??
  9. public ? void ?setCircleA(CircleA circleA)???
  10. {??
  11. ???????? this .circleA?=?circleA;??
  12. ????}??
  13. ???? public ? void ?c()?{??
  14. ????????circleA.a();??
  15. ????}??
  16. }??

?

3.2.2??????? Spring如何解決循環依賴

一、構造器循環依賴: 表示通過構造器注入構成的循環依賴,此依賴是無法解決的,只能拋出BeanCurrentlyInCreationException異常表示循環依賴。

如在創建CircleA類時,構造器需要CircleB類,那將去創建CircleB,在創建CircleB類時又發現需要CircleC類,則又去創建CircleC,最終在創建CircleC時發現又需要CircleA;從而形成一個環,沒辦法創建。

Spring容器將每一個正在創建的Bean 標識符放在一個“當前創建Bean池”中,Bean標識符在創建過程中將一直保持在這個池中,因此如果在創建Bean過程中發現自己已經在“當前創建Bean池”里時將拋出BeanCurrentlyInCreationException異常表示循環依賴;而對于創建完畢的Bean將從“當前創建Bean池”中清除掉。

?????? 1)首先讓我們看一下配置文件(chapter3/circleInjectByConstructor.xml):

?

java代碼:
  1. ??????
  2. <bean?id= "circleA" ? class = "cn.javass.spring.chapter3.bean.CircleA" >??
  3. <constructor-arg?index= "0" ?ref= "circleB" />??
  4. </bean>??
  5. <bean?id= "circleB" ? class = "cn.javass.spring.chapter3.bean.CircleB" >??
  6. <constructor-arg?index= "0" ?ref= "circleC" />??
  7. </bean>??
  8. <bean?id= "circleC" ? class = "cn.javass.spring.chapter3.bean.CircleC" >??
  9. <constructor-arg?index= "0" ?ref= "circleA" />??
  10. </bean>??
  11. ???

?

?????? 2)寫段測試代碼(cn.javass.spring.chapter3.CircleTest)測試一下吧:

?

java代碼:
  1. @Test (expected?=?BeanCurrentlyInCreationException. class )??
  2. public ? void ?testCircleByConstructor()? throws ?Throwable?{??
  3. try ?{??
  4. ?????? new ?ClassPathXmlApplicationContext( "chapter3/circleInjectByConstructor.xml" );??
  5. ????}??
  6. ???? catch ?(Exception?e)?{??
  7. ?????? //因為要在創建circle3時拋出; ??
  8. ??????Throwable?e1?=?e.getCause().getCause().getCause();??
  9. ?????? throw ?e1;??
  10. ????}??
  11. }??

?

?

?????? 讓我們分析一下吧:

?????? 1、Spring容器創建“circleA” Bean,首先去“當前創建Bean池”查找是否當前Bean正在創建,如果沒發現,則繼續準備其需要的構造器參數“circleB”,并將“circleA” 標識符放到“當前創建Bean池”;

?????? 2、Spring容器創建“circleB” Bean,首先去“當前創建Bean池”查找是否當前Bean正在創建,如果沒發現,則繼續準備其需要的構造器參數“circleC”,并將“circleB” 標識符放到“當前創建Bean池”;

3、Spring容器創建“circleC” Bean,首先去“當前創建Bean池”查找是否當前Bean正在創建,如果沒發現,則繼續準備其需要的構造器參數“circleA”,并將“circleC” 標識符放到“當前創建Bean池”;

4、到此為止Spring容器要去創建“circleA”Bean,發現該Bean 標識符在“當前創建Bean池”中,因為表示循環依賴,拋出BeanCurrentlyInCreationException。

??

二、setter循環依賴: 表示通過setter注入方式構成的循環依賴。

對于setter注入造成的依賴是通過Spring容器提前暴露剛完成構造器注入但未完成其他步驟(如setter注入)的Bean來完成的,而且只能解決單例作用域的Bean循環依賴。

?????? 如下代碼所示,通過提前暴露一個單例工廠方法,從而使其他Bean能引用到該Bean。

?

java代碼:
  1. addSingletonFactory(beanName,? new ?ObjectFactory()?{??
  2. ???? public ?Object?getObject()? throws ?BeansException?{??
  3. ???????? return ?getEarlyBeanReference(beanName,?mbd,?bean);??
  4. ????}??
  5. });??
  6. ???

?

?????? 具體步驟如下:

?????? 1、Spring容器創建單例“circleA” Bean,首先根據無參構造器創建Bean,并暴露一個“ObjectFactory ”用于返回一個提前暴露一個創建中的Bean,并將“circleA” 標識符放到“當前創建Bean池”;然后進行setter注入“circleB”;

?????? 2、Spring容器創建單例“circleB” Bean,首先根據無參構造器創建Bean,并暴露一個“ObjectFactory”用于返回一個提前暴露一個創建中的Bean,并將“circleB” 標識符放到“當前創建Bean池”,然后進行setter注入“circleC”;

?????? 3、Spring容器創建單例“circleC” Bean,首先根據無參構造器創建Bean,并暴露一個“ObjectFactory ”用于返回一個提前暴露一個創建中的Bean,并將“circleC” 標識符放到“當前創建Bean池”,然后進行setter注入“circleA”;進行注入“circleA”時由于提前暴露了“ObjectFactory”工廠從而使用它返回提前暴露一個創建中的Bean;

4、最后在依賴注入“circleB”和“circleA”,完成setter注入。

?

?????? 對于“prototype”作用域Bean,Spring容器無法完成依賴注入,因為“prototype”作用域的Bean,Spring容器不進行緩存,因此無法提前暴露一個創建中的Bean。

?

java代碼:
  1. <!--?定義Bean配置文件,注意scope都是“prototype”-->??
  2. <bean?id= "circleA" ? class = "cn.javass.spring.chapter3.bean.CircleA" ?scope= "prototype" >??
  3. ????????<property?name= "circleB" ?ref= "circleB" />??
  4. ???</bean>??
  5. ???<bean?id= "circleB" ? class = "cn.javass.spring.chapter3.bean.CircleB" ?scope= "prototype" >??
  6. ???????<property?name= "circleC" ?ref= "circleC" />??
  7. ???</bean>??
  8. ???<bean?id= "circleC" ? class = "cn.javass.spring.chapter3.bean.CircleC" ?scope= "prototype" >??
  9. ???????<property?name= "circleA" ?ref= "circleA" />??
  10. ???</bean>??

?

?

java代碼:
  1. //測試代碼cn.javass.spring.chapter3.CircleTest ??
  2. @Test (expected?=?BeanCurrentlyInCreationException. class )??
  3. public ? void ?testCircleBySetterAndPrototype?()? throws ?Throwable?{??
  4. ???? try ?{??
  5. ????????ClassPathXmlApplicationContext?ctx?=? new ?ClassPathXmlApplicationContext(??
  6. "chapter3/circleInjectBySetterAndPrototype.xml" );??
  7. ????????System.out.println(ctx.getBean( "circleA" ));??
  8. ????}??
  9. ???? catch ?(Exception?e)?{??
  10. ????????Throwable?e1?=?e.getCause().getCause().getCause();??
  11. ???????? throw ?e1;??
  12. ????}??
  13. }??

?

?????? 對于“singleton”作用域Bean,可以通過“setAllowCircularReferences(false);”來禁用循環引用:

?

java代碼:
  1. @Test (expected?=?BeanCurrentlyInCreationException. class )??
  2. public ? void ?testCircleBySetterAndSingleton2()? throws ?Throwable?{??
  3. ???? try ?{??
  4. ????????ClassPathXmlApplicationContext?ctx?=??
  5. new ?ClassPathXmlApplicationContext();??
  6. ????????ctx.setConfigLocation( "chapter3/circleInjectBySetterAndSingleton.xml" );??
  7. ????????ctx.refresh();??
  8. ????}??
  9. ???? catch ?(Exception?e)?{??
  10. ????????Throwable?e1?=?e.getCause().getCause().getCause();??
  11. ???????? throw ?e1;??
  12. ????}??
  13. }??

?

補充:出現循環依賴是設計上的問題,一定要避免!

請參考《敏捷軟件開發:原則、模式與實踐》中的“無環依賴”原則

包之間的依賴結構必須是一個直接的無環圖形(DAG)。也就是說,在依賴結構中不允許出現環(循環依賴)。 ?


?

?原創內容 轉載請注明出處【 http://sishuok.com/forum/blogPost/list/0/2448.html#7070

?

【第三章】 DI 之 3.2 循環依賴 ——跟我學spring3


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論