Spring源码解析之循环依赖
看个例子
CircularA类
@Service
public class CircularA {
@Autowired
private CircularB circularB;
public CircularB getCircularB() {
return circularB;
}
}
CircularB类
@Service
public class CircularB {
@Autowired
private CircularA circularA;
public CircularA getCircularA() {
return circularA;
}
}
测试方法
@Test
public void test3() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext("cn.com.dq");
CircularA circularA = (CircularA) applicationContext.getBean("circularA");
System.out.println(circularA.getCircularB());
CircularB circularB = (CircularB) applicationContext.getBean("circularB");
System.out.println(circularB.getCircularA());
}
结果输出

上述示例是我们编码中很常见的一种编码方式
循环依赖详解
了解循环依赖,得先了解bean的实例化过程,bean的实例化请看作者写的spring源码解析之bean的实例化
循环依赖流程

总结
A B循环依赖,优先实例化完成的是B,再是A,因为A在DI的时候需要B的实例,B没有实例化就需要实例化,但是B在实例化的时候,DI的时候需要A,此时的A已经提前暴露,放在三级缓存中,所以我们能够拿到A的实例,然后注入到B中,B实例化完成以后,返回B的实例,然后A完成DI后,A就完成了实例化。
几点思考
多例为什么不能循环依赖?
因为多例情况下,A在实例化的时候,在依赖注入B的时候,B的实例有多个,依赖哪一个?
所以多例情况下,是不能循环依赖的
spring在源码中也做了处理,在缓存中拿不到实例后,else首先就判断了多例,多例的循环依赖直接会报错
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
通过构造器注入的方式,能循环依赖吗?
看例子
CircularC 类
@Component
public class CircularC {
private CircularD circularD;
@Autowired
public CircularC(CircularD circularD) {
this.circularD = circularD;
}
}
CircularD 类
@Component
public class CircularD {
private CircularC circularC;
@Autowired
public CircularD(CircularC circularC) {
this.circularC = circularC;
}
}
执行结果

程序抛了异常
why?
C在实例化的时候,因为构造器的参数是引用类型,会触发beanFactory.getBean的操作,触发D类的实例化,此时D实例化,D实例化的时候同理会触发C的实例化,此时三个缓存中是没有任何的C的信息,因为三级缓存的暴露是在构造器实例化完成之后,所以在缓存中拿不到C,会继续走实例化流程,但是此时singletonsCurrentlyInCreation已经有了C,因为C在第一次实例化的时候,将beanName加入到了该容器中,此时就会抛出异常,源码如下:
protected void beforeSingletonCreation(String beanName) {
//把beanName添加到singletonsCurrentlyInCreation Set容器中,在这个集合里面的bean都是正在实例化的bean
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
所以构造器的方式的依赖注入是不能循环依赖的

浙公网安备 33010602011771号