亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

【第三章】 DI 之 3.2 循環(huán)依賴 ——跟我學(xué)spri

系統(tǒng) 1920 0

?

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

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

? 【第三章】 DI 之 3.2 循環(huán)依賴 ——跟我學(xué)spring3

圖3-5 循環(huán)引用

?????? 循環(huán)調(diào)用是無法解決的,除非有終結(jié)條件,否則就是死循環(huán),最終導(dǎo)致內(nèi)存溢出錯誤。

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

?

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如何解決循環(huán)依賴

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

如在創(chuàng)建CircleA類時,構(gòu)造器需要CircleB類,那將去創(chuàng)建CircleB,在創(chuàng)建CircleB類時又發(fā)現(xiàn)需要CircleC類,則又去創(chuàng)建CircleC,最終在創(chuàng)建CircleC時發(fā)現(xiàn)又需要CircleA;從而形成一個環(huán),沒辦法創(chuàng)建。

Spring容器將每一個正在創(chuàng)建的Bean 標(biāo)識符放在一個“當(dāng)前創(chuàng)建Bean池”中,Bean標(biāo)識符在創(chuàng)建過程中將一直保持在這個池中,因此如果在創(chuàng)建Bean過程中發(fā)現(xiàn)自己已經(jīng)在“當(dāng)前創(chuàng)建Bean池”里時將拋出BeanCurrentlyInCreationException異常表示循環(huán)依賴;而對于創(chuàng)建完畢的Bean將從“當(dāng)前創(chuàng)建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. ?????? //因?yàn)橐趧?chuàng)建circle3時拋出; ??
  8. ??????Throwable?e1?=?e.getCause().getCause().getCause();??
  9. ?????? throw ?e1;??
  10. ????}??
  11. }??

?

?

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

?????? 1、Spring容器創(chuàng)建“circleA” Bean,首先去“當(dāng)前創(chuàng)建Bean池”查找是否當(dāng)前Bean正在創(chuàng)建,如果沒發(fā)現(xiàn),則繼續(xù)準(zhǔn)備其需要的構(gòu)造器參數(shù)“circleB”,并將“circleA” 標(biāo)識符放到“當(dāng)前創(chuàng)建Bean池”;

?????? 2、Spring容器創(chuàng)建“circleB” Bean,首先去“當(dāng)前創(chuàng)建Bean池”查找是否當(dāng)前Bean正在創(chuàng)建,如果沒發(fā)現(xiàn),則繼續(xù)準(zhǔn)備其需要的構(gòu)造器參數(shù)“circleC”,并將“circleB” 標(biāo)識符放到“當(dāng)前創(chuàng)建Bean池”;

3、Spring容器創(chuàng)建“circleC” Bean,首先去“當(dāng)前創(chuàng)建Bean池”查找是否當(dāng)前Bean正在創(chuàng)建,如果沒發(fā)現(xiàn),則繼續(xù)準(zhǔn)備其需要的構(gòu)造器參數(shù)“circleA”,并將“circleC” 標(biāo)識符放到“當(dāng)前創(chuàng)建Bean池”;

4、到此為止Spring容器要去創(chuàng)建“circleA”Bean,發(fā)現(xiàn)該Bean 標(biāo)識符在“當(dāng)前創(chuàng)建Bean池”中,因?yàn)楸硎狙h(huán)依賴,拋出BeanCurrentlyInCreationException。

??

二、setter循環(huán)依賴: 表示通過setter注入方式構(gòu)成的循環(huán)依賴。

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

?????? 如下代碼所示,通過提前暴露一個單例工廠方法,從而使其他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容器創(chuàng)建單例“circleA” Bean,首先根據(jù)無參構(gòu)造器創(chuàng)建Bean,并暴露一個“ObjectFactory ”用于返回一個提前暴露一個創(chuàng)建中的Bean,并將“circleA” 標(biāo)識符放到“當(dāng)前創(chuàng)建Bean池”;然后進(jìn)行setter注入“circleB”;

?????? 2、Spring容器創(chuàng)建單例“circleB” Bean,首先根據(jù)無參構(gòu)造器創(chuàng)建Bean,并暴露一個“ObjectFactory”用于返回一個提前暴露一個創(chuàng)建中的Bean,并將“circleB” 標(biāo)識符放到“當(dāng)前創(chuàng)建Bean池”,然后進(jìn)行setter注入“circleC”;

?????? 3、Spring容器創(chuàng)建單例“circleC” Bean,首先根據(jù)無參構(gòu)造器創(chuàng)建Bean,并暴露一個“ObjectFactory ”用于返回一個提前暴露一個創(chuàng)建中的Bean,并將“circleC” 標(biāo)識符放到“當(dāng)前創(chuàng)建Bean池”,然后進(jìn)行setter注入“circleA”;進(jìn)行注入“circleA”時由于提前暴露了“ObjectFactory”工廠從而使用它返回提前暴露一個創(chuàng)建中的Bean;

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

?

?????? 對于“prototype”作用域Bean,Spring容器無法完成依賴注入,因?yàn)椤皃rototype”作用域的Bean,Spring容器不進(jìn)行緩存,因此無法提前暴露一個創(chuàng)建中的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);”來禁用循環(huán)引用:

?

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. }??

?

補(bǔ)充:出現(xiàn)循環(huán)依賴是設(shè)計上的問題,一定要避免!

請參考《敏捷軟件開發(fā):原則、模式與實(shí)踐》中的“無環(huán)依賴”原則

包之間的依賴結(jié)構(gòu)必須是一個直接的無環(huán)圖形(DAG)。也就是說,在依賴結(jié)構(gòu)中不允許出現(xiàn)環(huán)(循環(huán)依賴)。 ?


?

?原創(chuàng)內(nèi)容 轉(zhuǎn)載請注明出處【 http://sishuok.com/forum/blogPost/list/0/2448.html#7070

?

【第三章】 DI 之 3.2 循環(huán)依賴 ——跟我學(xué)spring3


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

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

【本文對您有幫助就好】

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

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 久久亚洲私人国产精品 | 日韩a级片 | 国产精品亚洲综合一区 | 亚洲欧美日韩在线不卡中文 | 一区二区三区在线 | 日本 | 中文精品久久久久中文 | 全毛片| www日韩中文字幕在线看 | 久久久久无码国产精品一区 | 欧美日韩一区二区三 | 久久亚洲高清观看 | 国外成人免费视频 | 逼毛片| 欧美日韩国产一区二区三区 | 欧美国产成人一区二区三区 | 日日夜夜欧美 | 国产精品揄拍一区二区久久 | 日韩欧美亚洲综合久久影院d3 | 手机看片在线精品观看 | 88国产精品欧美一区二区三区 | 日韩综合色| 高清成人| 日韩 欧美 亚洲 中文字幕 | 色综合小说天天综合网 | 亚洲视频国产 | 免费在线一区二区三区 | 午夜影院在线 | 国产香蕉尹人综合在线 | 亚洲一区二区三区高清 | 久草在线视频在线 | 欧美一区二区三区视视频 | 亚洲精品综合欧美一区二区三区 | 国产成版人视频网站免费下 | 欧美精品videossex最新 | 亚洲波多野结衣日韩在线 | 日本玖玖 | 91久久综合九色综合欧美亚洲 | 久久久综合视频 | 久久久中文字幕 | 亚洲精品亚洲人成在线 | 精品999久久久久久中文字幕 |