spring循环依赖的解决
当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,特性就是在每次获取实例的时候都会新建一个实例,这样对于实例就不存在缓存的情况,也就不能像单例那样通过三级缓存在解决循环依赖了。
- Spring循环依赖的解决办法——带源码分析
- Spring如何解决循环依赖
- Springboot循环依赖解决办法
- Spring中的循环依赖问题介绍及解决方法
- Spring中的循环依赖问题介绍及解决方法
- Spring-bean的循环依赖以及解决方式
- SPRING循环依赖(circular reference)的解决方法
- Spring如何解决循环依赖
- SPRING循环依赖(circular reference)的解决方法 [转贴]
- Spring的三层缓存,解决循环依赖问题
- 同学,Spring 是怎么解决循环依赖的?
- Spring如何解决循环依赖
- 解决spring循环依赖的问题:has been injected into other beans
- Spring-bean的循环依赖以及解决方式
- spring 源码探索--单例bean解决循环依赖问题
- Spring源码学习--Bean对象循环依赖问题解决(四)
- 同学,Spring 是怎么解决循环依赖的?
- Spring循环依赖及解决方式
- Spring-bean的循环依赖以及解决方式
- 解决spring循环依赖的问题:has been injected into other beans