三级缓存解决循环依赖
环境准备
A类中依赖B类
B类中依赖A类
Spring Bean的初始化大致分为两个阶段,第一个阶段,通过反射创建Bean,此时bean是前期对象,并没有赋值,也就是A类通过反射创建之后,他依赖的B类为null;第二个阶段,给早期对象赋值,也就是将A类中的B类初始化。
三级缓存解决循环依赖,三个缓存整个bean初始化的分布情况
1、set方法注入时,循环依赖实在实例化A对象之后,加入到三级缓存池中,给A对象赋值的 时候,发现有依赖B对象。此时去创建B对象,B对象实例化完成之后,加入到三级缓存池中。 此时缓存池的情况(1级:没有,2级没有,3级A\B对象的早期对象)。B对象在赋值的时候, 发现依赖A对象,于是创建A对象,发现三级缓存池中存在A对象,那么此时直接从三级缓存 中获取到A对象,并从三级缓存中删除A对象,且把A对象添加到二级缓存池中。缓存池情况 (1、没有,2、A对象,3、B对象),于是B对象的赋值完成,走后面的逻辑:将B对象添加到 一级缓存之中,并把2、3级缓存池中的B对象删除。缓存池状态(1、B完整对象,2、A的早期 对象,3、没有)。此时B对象完成走A对象的赋值操作,A对象赋值成功,走A对象的后期逻辑 ,添加到1级缓存池中,并把2、3级缓存池中的A对象删除,缓存池状态(1、A、B完整对象, 2、没有,3、没有)。整个A对象实例化完成。走实例化B对象时,发现一级缓存池中已经 存在,直接获取到返回。
2、属性注入的方式,与set方法注入方式相同,也能解决循环依赖问题。
3、构造方式注入时,在实例化A对象的时候,就发现依赖B对象,此时就去创建B对象了, 而此时的A对象并没有加入三级缓存池中,B对象实例化时,发现依赖A对象,又去创建 A对象了,发现A对象正在创建,抛出异常,循环依赖问题。
所以,一般情况下,属性注入以及set方法注入时,可解决循环依赖问题,构造函数注入时,无法解决循环依赖问题,当有循环依赖问题时,会抛出异常。
对于多例对象的循环依赖,spring没有添加缓存中,每次使用都要new一下,所以多例无法解决循环依赖