Spring 源碼閱讀-循環依賴

#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。

相關文章
相關標籤/搜索