1.什么是循环依赖?
1.1定义
循环依赖(Circular Dependency)指的是两个或多个类或组件彼此之间相互依赖,形成一个环状的依赖关系。这种情况下,如果不加以处理,就会导致依赖关系无法被正确地解析和初始化,从而引发程序运行时的问题或错误。例如,类A依赖于类B,而类B又依赖于类A,就形成了循环依赖。这种情况下,当系统尝试实例化类A时,需要先实例化类B,但实例化类B又需要实例化类A,就会导致一个无限循环或者无法顺利初始化的情况。
1.2循环类型
多者相互依赖
自身与自身依赖
2.spring容器中bean的生命周期
1,实例化
Spring容器将xml配置的的信息封装成一个BeanDefinition对象,存储到一个名为beanDefinitionMap的Map集合中去
2,初始化
属性填充(注入所依赖的属性值)[循环依赖问题所在]
Aware接口属性注入
执行BeanPostProcessor的before()方法
执行InitializingBean接口的初始化方法
执行 int-method自定义初始化方法
执行BeanPostProcessor的after()方法
3,使用操作
4,销毁
接口销毁
属性销毁
3.循环依赖的过程:
当A在初始化过程中需要B,但是singletonObjects中没有B , 此时,容器就会去创建B. 在创建B时又要去填充属性A , 但是singletonObjects中没有A,又会返回去创建A . 形成闭环循环往复 .( 自身与自身循环依赖时类似)
4.Spring框架的解决方案:三级缓存
4.1 什么是三级缓存?
-
三级缓存(singletonObjects): 在早期阶段,Spring创建一个对象的实例, 但是这个对象并没有完全初始化. 这时候, Spring将这个对象实例放入三级缓存中. 在这个阶段, Spring会记录对象的引用, 但不会注入属性或调用任何初始化方法.
-
二级缓存(earlySingletonObjects): 如果在依赖注入过程中发现循环依赖, Spring会在三级缓存中创建一个代理对象(proxy), 而不是真正的目标对象. 这个代理对象会暂时替代真实的对象引用,直到真实的对象初始化完成。
-
一级缓存(singletonFactories): 当对象的所有依赖关系都成功注入完成, 并且对象的初始化方法(如果有的话)被调用后, Spring将这个对象从三级缓存移到一级缓存中. 在这个阶段, 对象已经完全初始化, 可以安全地被其他对象引用和使用.
4.2 解决循环依赖过程
1.当A需要填充B时, 此时容器不仅会去创建B, 还会先将未完成的半成品A放在第三级缓存
2.在初始化B时, 会从三级缓存中拿取A , 并将A 放入二级缓存
3.B执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存并删除二三级缓存
4.A从一级缓存拿取B注入 ,再执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,并删除二三级缓存
至此,A B都完成Bean的创建
5.总结
三级缓存机制通过延迟Bean的完全初始化和使用代理对象的方式, 有效地解决了Spring中的循环依赖问题. 这种机制确保了对象依赖的正确注入顺序, 同时避免了初始化时可能导致的死锁或其他问题