您的位置:首页 > 编程语言 > Java开发

spring循环依赖的解决

2019-06-17 14:57 561 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/xwf1228/article/details/92627022

当A类中有B属性,B类中有A属性的时候,就会产生循环依赖。A在实例化的时候,引用了B,但是B么有实例化,所以就会先实例化B,这个时候发现B又引用了A,但是A还没有实例化,所以就造成了循环依赖。我们来看看spring是如何解决的

构造器循环依赖

代码

public class ClassA {

private ClassB B;

public ClassA(ClassB b) {
B = b;
}

public ClassA(){ }
public ClassB getB() {
return B;
}

public void setB(ClassB b) {
B = b;
}
}
public class ClassB {

private ClassA A;

public ClassB(ClassA a) {
A = a;
}
public ClassB(){ }

public ClassA getA() {
return A;
}

public void setA(ClassA a) {
A = a;
}
}

配置

<bean id="A" class="com.bean.ClassA" >
<constructor-arg index="0" ref="B"/>
</bean>

<bean id="B" class="com.bean.ClassB" >
<constructor-arg index="0" ref="A"/>
</bean>

测试类

public static void main(String[] args){
BeanFactoryTest t = new BeanFactoryTest();
t.testSimpleLoad();
}

public void testSimpleLoad() {
Resource resource = new ClassPathResource("beanFactoryTest.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);
ClassA a = (ClassA) beanFactory.getBean("A");
ClassB b = (ClassB) beanFactory.getBean("B");
}

测试结果

Error creating bean with name 'A' defined in class path resource [beanFactoryTest.xml]:
Cannot resolvereference to bean 'B' while setting constructor argument;
nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'B' defined in class path resource [beanFactoryTest.xml]:
Cannot resolve reference to bean 'A' while setting constructor argument;
nested exception is org.springframework.beans.factory.

从测试的结果中看出,构造器循环依赖并没有解决这个问题。

setter循环依赖

类不变,改变配置

<bean id="A" class="com.bean.ClassA" >
<property name="b" ref="B"/>
</bean>

<bean id="B" class="com.bean.ClassB" >
<property name="a" ref="A"/>
</bean>

同样的测试类,测试结果

六月 17, 2019 2:09:42 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [beanFactoryTest.xml]

Process finished with exit code 0

这里没有报错信息,setter方式解决了循环依赖的问题,我们来看看是如何解决的。
首先要知道一个bean的一个时序图

在上一文spring bean的实例化中我们看到一个类
AbstractBeanFactory 里面的doGetBean方法

跟踪这个getSingleton方法

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

singletonObjects,earlySingletonObjects,singletonFactories这3个Map作为三级缓存
这里的逻辑就是先找singletonObjects中是否存在bean
如果不存在,然后在找earlySingletonObjects中是否存在
如果还是不存在,在singletonFactories中找到对应的工厂类,然后在用工厂类来实例化,实例化后放入earlySingletonObjects,下次查找就直接在earlySingletonObjects中能找到了。
根据时序图,由于单例工厂在属性引用前就已经产生了,所以在这里可以直接用singletonFactories来创建对应的实例,实例肯能还不完整,单起码可以先引用起来。

setter方式,prototype作用域

修改配置文件

<bean id="A" scope="prototype" class="com.bean.ClassA" >
<property name="b" ref="B"/>
</bean>

<bean id="B" scope="prototype" class="com.bean.ClassB" >
<property name="a" ref="A"/>
</bean>

测试结果

Error creating bean with name 'A' defined in class path resource [beanFactoryTest.xml]:
Cannot resolvereference to bean 'B' while setting constructor argument;
nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'B' defined in class path resource [beanFactoryTest.xml]:
Cannot resolve reference to bean 'A' while setting constructor argument;
nested exception is org.springframework.beans.factory.

依然会有循环依赖的报错
对于“prototype”作用域的Bean,特性就是在每次获取实例的时候都会新建一个实例,这样对于实例就不存在缓存的情况,也就不能像单例那样通过三级缓存在解决循环依赖了。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: