Skip to content

Latest commit

 

History

History
72 lines (49 loc) · 4.2 KB

三级缓存.md

File metadata and controls

72 lines (49 loc) · 4.2 KB

三级缓存概述

Spring 中引入第三级缓存singletonFactories的目的主要是为了解决循环依赖问题。

当 bean A 依赖 bean B,而 bean B 同样依赖 bean A 时,就产生了循环依赖。此时,如果简单地将二者的实例相互注入,就会陷入无限递归。

为解决这个问题,Spring 引入了三级缓存:

  1. singletonObjects:用于普通的依赖查找,存放完全初始化好的 bean 实例。
  2. earlySingletonObjects:用于解决循环依赖,将未完全初始化的 bean 实例提前暴露,以满足循环依赖的依赖查找。
  3. singletonFactories:用于解决循环依赖,当发现依赖循环时,会通过 ObjectFactory 进行懒加载,创建一个临时的 bean 实例至 earlySingletonObjects,继续完成后续的依赖注入。

当发现循环依赖时:

  1. 从 singletonFactories 获取对应的 ObjectFactory。
  2. 通过 ObjectFactory 进行懒加载,创建一个临时 bean 实例至 earlySingletonObjects。
  3. 将 earlySingletonObjects 中的临时实例注入至依赖它的 bean。
  4. 完成所有 bean 的初始化后,从 earlySingletonObjects 中清除临时实例,将完全初始化后的实例存入 singletonObjects。
  5. 后续的依赖查找直接从 singletonObjects 中获取实例。

二级缓存

二级缓存的引入为 Spring 容器带来了解决循环依赖问题的能力,使依赖注入的过程更加灵活可靠。但同时也增加了容器对 bean 生命周期管理的难度,它需要在适当的时机将 bean 的实例添加至二级缓存与清除二级缓存。

  1. 使依赖注入的目标 bean 可以在完全初始化之前被依赖。

在创建 bean 的过程中,如果发现存在循环依赖,即其他 bean 依赖当前正在创建的 bean,此时就需要将当前 bean 提前暴露出来,让依赖它的 bean 可以使用。 这就是 earlySingletonObjects 存在的首要原因。它存储了还未完全初始化的 bean,但已经可以被依赖使用。如果不使用二级缓存,依赖当前 bean 的其他 bean 在初始化时无法获得它的实例,这会导致依赖注入失败,产生循环依赖问题。

  1. 在目标 bean 完全初始化后,需要从二级缓存中清除它的实例。

earlySingletonObjects 中存储的实例还未完全初始化,只是为了解决循环依赖问题暴露出来的临时实例。 一旦 bean 的全部初始化逻辑执行完成,需要将其从 earlySingletonObjects 移除,然后放入 singletonObjects。由于 earlySingletonObjects 中的实例未完全初始化,它们不应该被当做 bean 的最终实例使用。所以在初始化完成后,必须将其清除,这是使用二级缓存的第二个原因。如果不在初始化完成后清除 earlySingletonObjects 中的实例,其中的实例仍然可能在系统中流转,这会产生难以预料的问题。

三级缓存解决代理+解耦的问题

@Component
public class A {
    @Autowired
    private B b;
}

@Component
@Aspect
public class B {  // B 会被代理
    @Autowired
    private A a; 
}
  1. 创建A
  2. A 依赖 B,开始创建 B
  3. 此时由于 @Aspect 注解,B 会被代理,所以获取到的不是 B 的真实对象
  4. 代理对象也依赖 A,但是 A 此时还未完全初始化
  5. 又开始创建 A,产生循环。

而引入三级缓存 singletonFactories 后,问题就解决了:

  1. 创建 A,注册到 earlySingletonObjects(二级缓存)
  2. A 依赖 B,开始创建 B
  3. B 会被代理,代理对象也依赖 A
  4. 此时代理对象从 singletonFactories(三级缓存) 获取一个可以创建 A 的工厂
  5. 代理对象使用工厂创建 A,完成初始化
  6. A 从 singletonFactories(三级缓存 ) 获取 B 的工厂,创建 B,完成初始化

所以,singletonFactories (三级缓存 )不仅封装了对其他 bean 的依赖,也隐藏了 bean 是否被代理的状态。 无论 B 是否被代理,A 都可以通过 singletonFactories (三级缓存 )获取 B 的工厂,然后再获取 B 的代理对象或目标对象。这也体现了高内聚和解耦的思想,通过 singletonFactories 隔离了 bean 与代理对象之间的依赖关系。所以,总结来说,三级缓存不仅可以解决循环依赖的问题,也可以很好的解决代理造成的依赖问题。这也是 Spring 框架采用三级缓存的另一个目的。