<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 【第三章】 DI 之 3.2 循環依賴 ——跟我學spring3 ### 3.2.1? 什么是循環依賴 循環依賴就是循環引用,就是兩個或多個Bean相互之間的持有對方,比如CircleA引用CircleB,CircleB引用CircleC,CircleC引用CircleA,則它們最終反映為一個環。此處不是循環調用,循環調用是方法之間的環調用。如圖3-5所示: ![](https://box.kancloud.cn/2016-05-12_57348071a4095.JPG) 圖3-5 循環引用 循環調用是無法解決的,除非有終結條件,否則就是死循環,最終導致內存溢出錯誤。 Spring容器循環依賴包括構造器循環依賴和setter循環依賴,那Spring容器如何解決循環依賴呢?首先讓我們來定義循環引用類: 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. }?? 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. }?? 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): 2. &lt;bean?id="circleA"?class="cn.javass.spring.chapter3.bean.CircleA"&gt;?? 3. &lt;constructor-arg?index="0"?ref="circleB"/&gt;?? 4. &lt;/bean&gt;?? 5. &lt;bean?id="circleB"?class="cn.javass.spring.chapter3.bean.CircleB"&gt;?? 6. &lt;constructor-arg?index="0"?ref="circleC"/&gt;?? 7. &lt;/bean&gt;?? 8. &lt;bean?id="circleC"?class="cn.javass.spring.chapter3.bean.CircleC"&gt;?? 9. &lt;constructor-arg?index="0"?ref="circleA"/&gt;?? 10. &lt;/bean&gt;?? 2)寫段測試代碼(cn.javass.spring.chapter3.CircleTest)測試一下吧: 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。 1. addSingletonFactory(beanName,?new?ObjectFactory()?{?? 2. public?Object?getObject()?throws?BeansException?{?? 3. return?getEarlyBeanReference(beanName,?mbd,?bean);?? 4. }?? 5. });?? 具體步驟如下: 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。 1. &lt;!--?定義Bean配置文件,注意scope都是“prototype”--&gt;?? 2. &lt;bean?id="circleA"?class="cn.javass.spring.chapter3.bean.CircleA"?scope="prototype"&gt;?? 3. &lt;property?name="circleB"?ref="circleB"/&gt;?? 4. &lt;/bean&gt;?? 5. &lt;bean?id="circleB"?class="cn.javass.spring.chapter3.bean.CircleB"?scope="prototype"&gt;?? 6. &lt;property?name="circleC"?ref="circleC"/&gt;?? 7. &lt;/bean&gt;?? 8. &lt;bean?id="circleC"?class="cn.javass.spring.chapter3.bean.CircleC"?scope="prototype"&gt;?? 9. &lt;property?name="circleA"?ref="circleA"/&gt;?? 10. &lt;/bean&gt;?? 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);”來禁用循環引用: 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](http://sishuok.com/forum/blogPost/list/0/2448.html#7070)】
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看