Spring只能解决的循环依赖


Spring只能解决Setter注入的单例模式下的循环依赖问题,要想解决循环依赖必须满足2个条件:

1. 需要用于提前曝光的缓存
2. 属性的注入时机必须发生在提前曝光动作之后,不管是填充还是初始化都行,总之不能在实例化,因为提前曝光动作在实例化之后

解决方案


当然,Spring 是不会让这种情况发生的。在容器发现 beanB 依赖于 beanA 时,容器会获取 beanA对象的一个 早期的引用(early reference),并把这个早期引用注入到 beanB 中,让 beanB 先完成实例化。beanB 完成实例化,beanA 就可以获取到 beanB 的引用,beanA 随之完成实例化.



singletonsCurrentLyInCreation容器是装载正在实例化的Bean对象,主要是用来做校验的,校验有参构造函数循环依赖的话,就会在这个容器找到,所以就会报错.
在Bean实例化完成之后就会删除singletonsCurrentLyInCreation容器里面对应的实例化完成的Bean,然后给这个实例化完成的Bean放入一个叫singletonObjects的一级缓存
一级缓存里面的实例是在Bean已经完全创建成功之后就会放入在里面,然后就会给二级缓存和三级缓存里面的对应Bean删除掉.



单例循环依赖
1.A实例化,A调用构造器 , 然后A往singletonsCurrentLyInCreation容器里面存放, 三级缓存里面添加值,
2.然后会触发A类里面的B成员类的IOC,DI过程,会调用getBean方法,

3.此时B类开始实例化,调用B的构造函数,然后B往三级缓存里面放,
4.然后B类会触发IOC,DI过程,此时会调用A类的getBean方法.
5.此时又有A类的实例化开始,此时从三级缓存里面获取值(因为第一步骤A已经往三级缓存里面放值了),获取的值是A类的完成,已经A类里面B成员类为null的值.
6.然后B类实例化结束
7.然后A类实例化结束.
整个过程结束.

无参构造函数属性的单例方式的循环依赖是允许的,其它的所有循环依赖不允许

有参构造函数注入的方式会报错,原型模式的循环依赖也不行,会报错.




要想看源码主要看
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)