spring三级缓存

时间:2024-10-08 20:00:38

1. 三级缓存目的

解决spring单例bean的循环依赖问题。

循环依赖是指多个bean之间相互依赖。例如,Bean A依赖Bean B,同时Bean B又依赖Bean A。

2. 原理和机制

三级缓存本质上就是三个Map。

  • 一级缓存(singletonObjects):存放完全初始化后的单例Bean。正常情况下,获取单例Bean时会直接从这个缓存中获取。在循环依赖场景下,单例Bean还未完全初始化就可能被其他Bean引用,所以一级缓存不能单独解决循环依赖问题。
  • 二级缓存(earlySingletonObjects):存放早期未完全初始化的单例Bean。在解决循环依赖时,它可以在一定程度上打破循环。但解决不了有AOP代理的情况,因此需要第三级缓存。
  • 三级缓存(singletonFactories):存放ObjectFactory对象。在循环依赖的情况下,当需要获取早期Bean时,可以通过这个ObjectFactory来创建。在涉及AOP时,ObjectFactory创建带有AOP的早期引用,解决循环依赖并保证AOP。

3. 举个例子

假设有两个bean A和B,互相独立,在创建他们的时候,只会用到一级缓存。

假设有两个bean A和B,A里用了B,B里用了A,就形成了循环依赖,在创建他们的时候,就会用到三级缓存机制。具体如下:

  1. 实例化A
  2. 给A的属性赋值,发现A中有个B属性
  3. 从一级缓存找B,没找到B,从二级缓存找B,也没找到,从三级缓存找B,还没找到
  4. 把A的Factory放入到第三级缓存中
  5. 实例化B
  6. 给B的属性赋值,发现B中有个A属性
  7. 从一级缓存找A,没找到A,从二级缓存找A,也没找到,从三级缓存找A,找到了!
  8. 用三级缓存里A的Factory生成A的早期对象(如果A有AOP,Factory生成A的时候要把AOP处理好)
  9. A的早期对象放入到二级缓存,删除三级缓存里的A的Factory
  10. 完成B的属性赋值(依赖注入),将B放入一级缓存
  11. 继续回到第2步,完成A中B属性的注入
  12. 将A也放入一级缓存

4. 三级缓存不能解决哪些循环依赖?

  1. 非单例bean:如prototype类型的bean有循环依赖,spring会直接抛异常出来。
  2. 构造函数注入:多个bean通过构造函数互相依赖,这种三级缓存也解决不了,因为三级缓存第一步就是要用构造函数来实例化bean,这一步就跪了。
  3. 跨容器bean:多个spring容器之间的bean相互依赖,这种三级缓存也解决不了,因为三级缓存是在某个容器内部的。
  4. 非标准AOP代理场景:如自定义的动态代理生成器,并且该代理生成过程与Spring默认的AOP代理和bean创建顺序有冲突,可能会出现三级缓存无法解决的循环依赖情况。比如A有AOP,但这个AOP需要依赖另一个机制来确定是否要加AOP,而这个机制是在A被三级缓存的Factory生成后才给出结果的,那这个AOP就不能被正确地加上。

5. 二级缓存可以吗?

二级缓存里存放的是固化了的一个对象,而三级缓存里放的是创建对象的“代码逻辑”,它可以根据具体情况去处理AOP。