解释
依赖:DI(依赖注入)中的依赖,某一类中的属性需要在创建对象是给其赋值,这个依赖具体指的就是那个值
循环:当依赖是自定义类(javabean)时,A类中有一个B类型的外部属性b,B类中有个A类型的外部属性a
循环依赖:当spring容器创建A类对象或创建B类对象时,以创建A类对象为例,实例化A时需要B类对象,那就需要创建B类对象,创建B类对象时又需要A类对象,但是创建A类对象又需要B类对象,导致两个对象创建时一直等待依赖双方的对象创建出来,僵持不下,导致类似死锁的局面
循环依赖出现的场景
DI(依赖注入),多个类之间相互需要彼此作为创建完整对象的部分内容,相互之间的依赖关系形成闭环
循环依赖的成因
spring容器创建完整的bean对象需要经历的各个阶段
以A类依赖B类,B类依赖A类,具体看依赖循环成因
spring容器创建A对象,在进行初始化时需要属性赋值时(给外部属性赋B对象),停止继续初始化,转头去容器中找是否有B对象,没有,则创建B对象,当走到属性赋值时需要A对象,发现A类和B类有循环依赖关系报错。
BeanCreationException: Error creating bean with name 'a' defined in class path resource [applicationConfig.xml]: Cannot resolve reference to bean 'b' while setting constructor argument;
创建A对象时未解决与B的依赖关系
BeanCreationException: Error creating bean with name 'b' defined in class path resource [applicationConfig.xml]: Cannot resolve reference to bean 'a' while setting constructor argument
创建B对象时未解决与A的依赖关系
BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
创建当前bean时可能有循环依赖问题未解决
当依赖注入方式采用构造方法,出现上面错误信息
当依赖注入采用set方法时,spring容器自动处理了依赖注入问题
解决办法
依赖注入时,有类与类之间相互依赖的情况,选择set注入方式,spring容器自动解决循环注入问题
解决原理
三级缓存
三级缓存:存未被引用的bean半成品
二级缓存:存被引用的bean半成品
一级缓存:存完整的bean
当A对象初始化进入到属性赋值时,发现需要B对象,去三级缓存找没找到,将自己这个半成品存到三级缓存
B对象创建进入到属性赋值阶段,发现需要A对象,去三级缓存找找到了,走完初始化得到完整的B对象放入一级缓存,删除二、三级缓存中的B对象半成品,A对象半成品从三级到二级
A继续属性赋值,三级、二级都没有B对象在一级缓存中找到,A对象继续其他步骤完成创建,删除二、三级缓存中A的内容,完整的A对象放入一级缓存
疑惑地点:A对象中的B貌似是半成品,B对象中的A也貌似是半成品。完成和半成品只是对象的两个时期的状态,最终引用的都是地址,当A对象创建走完初始化全过程,B对象原来指向“半成品”最终就指向完成品,同理A对象中指向的也是完整的B对象