spring迴圈依賴
阿新 • • 發佈:2019-05-25
迴圈依賴解決
constructor(此種無法解決)
(看完sertter之後再來看這部分吧) 我想看過下部分setter解決迴圈依賴的實現之後,肯定有想法為啥constructor無法實現,我們同樣可以提前曝光一個SingletonFactory(以下簡稱fac)噻? 其實不然,當然,我們想法是沒有問題的,我們當然可以提前暴露一個fac,但是為什麼此種方式不行。 首先我們分析一下為什麼setter能夠實現,我們知道在setter中是在bean例項化完畢之後, 這裡很重要,因為是例項化之後,所有這個時候A其實是已經存在了,只是還沒有填充屬性而已, 在populateBean填充屬性的時候發現沒有B,然後再去建立B, 這個時候B可以通過提前曝光的fac拿到的A例項, 看清楚了,是拿到的A的例項,不是fac。這種情況A在填充完屬性之後,B持有的A地址不會變, 所以這種情況提前曝光可以解決迴圈依賴。 再來看constructor的情況,我們說了,我們當然可以天暴露一個fac(可以在建構函式執行前暴露), 但是當我們在初始化B,為B填充屬性A的時候,你覺得我們能從fac中拿到一個A的地址嗎?當然不能咯, 因為A的constructor並未執行完成,這種情況下,A是沒有分配到地址的,也就是說A並不存在,而我們只有一個fac, 這個fac的getObject是沒辦法獲取到A的,因為A還不存在啊,但是B需要的是一個A型別的屬性,而不是一個Factory, 所以無法注入!無法注入怎麼辦,無法注入當然就無法實現咯!
setter
提前暴露一個單例bean的工廠方法,使其他bean能引用到該bean。
//AbstractAutowireCapableBeanFactory.java protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) { ... //提前暴露條件,當前例項是單例 && 允許迴圈依賴 && 當前例項正在建立中 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { ... addSingletonFactory(beanName, new ObjectFactory<Object>() { public Object getObject() throws BeansException { //對bean再一次依賴引用,主要應用SmartInstantiationAware BeanPostProcessor, //AOP就是在這裡將advice動態之織入bean中,若沒有則直接返回bean,不作任何處理 return getEarlyBeanReference(beanName, mbd, bean); } }); } ... }
code
<bean id="circleA" class="com.wt.test.circle.CircleA"> <property name="circleB" ref="circleB"/> </bean> <bean id="circleB" class="com.wt.test.circle.CircleB"> <property name="circleA" ref="circleA"/> </bean>
private static void circleSolution() {
ClassPathXmlApplicationContext x = new ClassPathXmlApplicationContext("application-circle.xml");
CircleA a = x.getBean(CircleA.class);
CircleB b = x.getBean(CircleB.class);
System.out.println(a);
System.out.println(b);
System.out.println(a.getCircleB() == b);
System.out.println(b.getCircleA() == a);
}
結果
prototype模式
xml
<bean id="circleA" class="com.wt.test.circle.CircleA" scope="prototype">
<property name="circleB" ref="circleB"/>
</bean>
<bean id="circleB" class="com.wt.test.circle.CircleB" scope="prototype">
<property name="circleA" ref="circleA"/>
</bean>
結果
注意:只有在單例模式下才能解決迴圈依賴,prototype作用域的bean是無法完成迴圈依賴注入的,因為Spring容器不進行快取prototype作用域的bean,因此無法提前暴露出一個建立中的bean!