关于spring:Spring是如何解决的循环依赖

3次阅读

共计 1129 个字符,预计需要花费 3 分钟才能阅读完成。

Spring 解决循环依赖是有前置条件的:

  1. 呈现循环依赖的 Bean 必须要是 单例
  2. 依赖注入的形式 不能全是结构器注入 的形式
依赖状况 依赖注入形式 循环依赖是否被解决
AB 相互依赖(循环依赖) 均采纳 setter 办法注入
AB 相互依赖(循环依赖) 均采纳结构器注入
AB 相互依赖(循环依赖) A 中注入 B 的形式为 setter 办法,B 中注入 A 的形式为结构器
AB 相互依赖(循环依赖) B 中注入 A 的形式为 setter 办法,A 中注入 B 的形式为结构器

创立 A 的过程实际上就是调用 getBean 办法,这个办法有两层含意

  1. 创立一个新的 Bean
  2. 缓存 中获取到曾经被创立的对象

????

Spring 通过 三级缓存解决了循环依赖 ,其中一级缓存为 单例池 singletonObjects), 二级缓存为 晚期曝光对象 earlySingletonObjects),三级缓存为 晚期曝光对象工厂singletonFactories)。

getSingleton(beanName, true)这个办法实际上就是到缓存中尝试去获取 Bean,整个缓存分为三级

  1. singletonObjects,一级缓存,存储的是所有 曾经齐全创立好了的单例 Bean
  2. earlySingletonObjects,实现实例化,然而还未进行属性注入及初始化的对象
  3. singletonFactories,提前裸露的一个单例工厂,二级缓存中存储的就是从这个工厂中获取到的对象

当 A、B 两个类产生循环援用时,在 A 实现实例化后,就 应用实例化后的对象去创立一个对象工厂 并增加到三级缓存中,如果 A 被 AOP 代理,那么通过这个工厂获取到的就是 A 代理后的对象,如果 A 没有被 AOP 代理,那么这个工厂获取到的就是 A 实例化的对象。

当 A 进行属性注入时,会去创立 B,同时 B 又依赖了 A,所以创立 B 的同时又会去调用 getBean(a) 来获取须要的依赖,此时的 getBean(a) 会从缓存中获取:
第一步,先获取到三级缓存中的工厂;
第二步,调用对象工工厂的 getObject 办法来获取到对应的对象,失去这个对象后将其注入到 B 中。紧接着 B 会走完它的生命周期流程,包含初始化、后置处理器等。

当 B 创立完后,会将 B 再注入到 A 中,此时 A 再实现它的整个生命周期。至此,循环依赖完结!

面试官:”为什么要应用三级缓存呢?二级缓存能解决循环依赖吗?“
答:如果要应用二级缓存解决循环依赖,意味着 所有 Bean 在实例化后就要实现 AOP 代理 ,这样违反了 Spring 设计的准则,Spring 在设计之初就是通过AnnotationAwareAspectJAutoProxyCreator 这个后置处理器来在 Bean 生命周期的最初一步来实现 AOP 代理,而不是在实例化后就立马进行 AOP 代理。

转载:讲一讲 Spring 中的循环依赖

正文完
 0