#Spring 源碼閱讀-循環依賴spring
##一. 循環依賴spring-mvc
Spring中產生循環依賴有三種狀況緩存
1.構造器循環依賴mvc
代碼示例this
public class ModelA { private ModelB modelB; public ModelA(ModelB modelB){ this.modelB=modelB; } public ModelB getModelB() { return modelB; } public void setModelB(ModelB modelB) { this.modelB = modelB; } } public class ModelB { private ModelC modelC; public ModelB(ModelC modelc){ this.modelC=modelc; } public ModelC getModelC() { return modelC; } public void setModelC(ModelC modelC) { this.modelC = modelC; } } public class ModelC { private ModelA modelA; public ModelA getModelA() { return modelA; } public void setModelA(ModelA modelA) { this.modelA = modelA; } public ModelC(ModelA modelA){ this.modelA=modelA; } } //配置文件 <bean id="modela" class="com.wm.ModelA"> <constructor-arg index="0" ref="modelb"/> </bean> <bean id="modelb" class="com.wm.ModelB"> <constructor-arg index="0" ref="modelc"/> </bean> <bean id="modelc" class="com.wm.ModelC"> <constructor-arg index="0" ref="modela"/> </bean> //Client ApplicationContext context=new ClassPathXmlApplicationContext ("/spring/spring-mvc.xml"); ModelC modelC=(ModelC)context.getBean("modelc");
錯誤信息 Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'modela': Requested bean is currently in creation: Is there an unresolvable circular reference?prototype
分析code
Spring容器將每個正在建立的Bean 標識符放在一個「當前建立Bean池」中,Bean標識符在建立過程當中將一直保持在這個池中,所以若是在建立Bean過程當中發現本身已經在「當前建立Bean池」裏時將拋出BeanCurrentlyInCreationException異常表示循環依賴;而對於建立完畢的Bean將從「當前建立Bean池」中清除掉。xml
一、Spring容器建立「modelA」 Bean,首先去「當前建立Bean池」查找是否當前Bean正在建立,若是沒發現,則繼續準備其須要的構造器參數「modelB」,並將「modelA」 標識符放到「當前建立Bean池」;ci
二、Spring容器建立「modelB」 Bean,首先去「當前建立Bean池」查找是否當前Bean正在建立,若是沒發現,則繼續準備其須要的構造器參數「modelC」,並將「modelB」 標識符放到「當前建立Bean池」;作用域
三、Spring容器建立「modelC」 Bean,首先去「當前建立Bean池」查找是否當前Bean正在建立,若是沒發現,則繼續準備其須要的構造器參數「modelA」,並將「modelC」 標識符放到「當前建立Bean池」;
四、到此爲止Spring容器要去建立「modelA」Bean,發現該Bean 標識符在「當前建立Bean池」中,由於表示循環依賴,拋出BeanCurrentlyInCreationException。
2.Setter循環依賴
分析 一、Spring容器建立單例「modelA」Bean,首先根據無參構造器建立Bean,並暴露一個「ObjectFactory」用於返回一個提早暴露一個建立中的Bean,並將「modelA」標識符放到「當前建立Bean池」;而後進行setter注入「modelB」;
二、Spring容器建立單例「modelB」Bean,首先根據無參構造器建立Bean,並暴露一個「ObjectFactory」用於返回一個提早暴露一個建立中的Bean,並將「modelB」 標識符放到「當前建立Bean池」,而後進行setter注入「modelC」;
三、Spring容器建立單例「modelC」Bean,首先根據無參構造器建立Bean,並暴露一個「ObjectFactory 」用於返回一個提早暴露一個建立中的Bean,並將「modelC」 標識符放到「當前建立Bean池」,而後進行setter注入「modelA」;進行注入「modelA」時因爲提早暴露了「ObjectFactory」工廠從而使用它返回提早暴露一個建立中的Bean;
四、最後再依賴注入「modelB」和「modelA」,完成setter注入。
3.prototype循環依賴
//配置文件 <bean id="modela" class="com.wm.ModelA" scope="prototype"> <property name="modelB" ref="modelb" /> </bean> <bean id="modelb" class="com.wm.ModelB" scope="prototype"> <property name="modelC" ref="modelc"/> </bean> <bean id="modelc" class="com.wm.ModelC" scope="prototype"> <property name="modelA" ref="modela"/> </bean>
錯誤信息 Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'modela': Requested bean is currently in creation: Is there an unresolvable circular reference?
緣由
對於「prototype」做用域Bean。Spring容器沒法完成依賴注入,因爲「prototype」做用域的Bean,Spring容器不進行緩存,所以沒法提早暴露一個建立中的Bean。