dede医院网站模板,小企业网站建设流程,绍兴在线制作网站,西安推广网站循环依赖问题是在对象之间存在相互依赖关系#xff0c;形成一个闭环#xff0c;导致无法准确的完成对象的创建和初始化#xff0c;当两个或多个对象彼此之间相互引用#xff0c;这种相互引用形成一个循环时#xff0c;就可能出现循环依赖问题。
在 Spring 框架中#xf…循环依赖问题是在对象之间存在相互依赖关系形成一个闭环导致无法准确的完成对象的创建和初始化当两个或多个对象彼此之间相互引用这种相互引用形成一个循环时就可能出现循环依赖问题。
在 Spring 框架中循环依赖Circular Dependency是指两个或多个 Bean 之间互相依赖导致依赖关系形成一个闭环。例如
Bean A 依赖 Bean B。Bean B 又依赖 Bean A。
这种依赖会导致 Spring 无法正确实例化和初始化这些 Bean因为在创建一个 Bean 时需要先创建它所依赖的 Bean而它依赖的 Bean 又反过来依赖它 如何解决循环依赖
单例作用域的循环依赖依赖于三级缓存来解决问题
一级缓存Singleton Objects 存放已经完全初始化的单例 Bean。二级缓存Early Singleton Objects 存放原始的、尚未完全初始化的 Bean 实例暴露了部分 Bean 的引用。三级缓存Singleton Factories 存放 Bean 的对象工厂延迟初始化 解决循环依赖的前提条件
互相依赖的Bean必须要是单例的Bean依赖注入的方式不能都是构造函数注入的方式 当遇到循环依赖时Spring 采取以下步骤
1.创建 Bean 的原始实例
Spring 首先根据构造器或工厂方法创建 Bean 的原始实例即还未完成依赖注入和初始化。这个实例此时不会立即暴露给其他 Bean。将 ObjectFactory 放入三级缓存Spring 会将一个能够生成该 Bean 的工厂对象ObjectFactory放入三级缓存singletonFactories。
2.检测并解决依赖
如果依赖的 Bean 已经创建则直接从一级缓存singletonObjects中获取。如果依赖的 Bean 尚未完全初始化但已创建原始实例Spring 会从三级缓存中通过 ObjectFactory 获取早期引用并将其放入二级缓存earlySingletonObjects。从二级缓存中获取的 Bean 引用可能是代理对象用于避免后续初始化重复。
3.完成依赖注入
使用从一级缓存或二级缓存中获取的 Bean 引用完成当前 Bean 的依赖注入。
4.完成 Bean 初始化
初始化后Spring 会将完全初始化的 Bean 放入一级缓存singletonObjects并从二级缓存和三级缓存中移除相关引用 为什么一定要使用三级缓存
1.首先一级缓存一定是要的因为Bean是单例模式需要存放到某个容器中而一级缓存就是这个缓存容器。
2.二级缓存可以不要我们可以把半成品Bean放到一级缓存中但这样需要给一级缓存中添加标识标识哪些是完整对象哪些都是半成品对象这样有几个问题 1.增加了Spring源码设计复杂性。 2.在查询时需要先判断标识查询效率变低了。 3.违反单一设计原则。
因此为了解决这些问题二级缓存也是必须要的。
3.三级缓存也可以不要但这样也有一个问题那就是Spring的设计模式中在生成代理时为了实现对象初始化和生成代理对象的解耦 所以代理对象是在AnnotationAwareAspectJAutoProxyCreator 这个后置处理的最后一步生成AOP代理对象的。
如果不要三级缓存那么我们需要在所有类创建之前先将代理类创建出来这样遇到循环依赖就可以直接拿出代理对象来使用了但这种方式的缺点是打破了原理Spring 的设计理念。实现对象初始化和生成代理对象的解耦
所以最优方案是不提前创建代理对象而是使用三级缓存存储创建对象的表达式等遇到循环依赖再按照Spring的设计模式来生成代理对象。