Spring的三级缓存解决循环依赖

Spring的三级缓存以及循环依赖

什么是循环依赖:

假设我们有两个类 A 和 B,类A和类B的实例互为成员变量即为循环依赖。

image-20240808174951266

什么情况下会出现死循环?

当 Spring 框架启动后,开始根据注解将类 A 实例化并注入到容器当中,在实例化 A 之后就会尝试获取类 B 的实例来进行依赖注入。

image-20240808175210294由于类 B 并没有进行实例化,那么 Spring 框架就会去实例化类 B,同样的也会需要将类 A 的依赖注入到类 B 的实例中最终,无论先实例化哪个类,都会形成死循环。

image-20240808175218723

image-20240808175225835

三级缓存是什么

①一级缓存:单例池,缓存已经经历了完整的生命周期,已经初始化完成的bean对象

②二级缓存:缓存早期的bean对象(生命周期还没走完)

③三级缓存:缓存的是ObjectFactory,表示对象工厂,用来创建某个对象的

缓存名称 源码名称 说明
一级缓存 singletonObjects 单例池,缓存已经初始化完成的bean对象。
二级缓存 earlySingletonObjects 缓存早期的bean对象。(例如:只进行了实例化,还没有进行依赖注入)
三级缓存 singletonFactories 缓存的是ObjectFactory,表示对象工厂,用来创建某个对象的。

image-20240808180700337

第一,先实例A对象,同时会创建ObjectFactory对象存入三级缓存singletonFactories

第二,A在初始化的时候需要B对象,这个走B的创建的逻辑

第三,B实例化完成,也会创建ObjectFactory对象存入三级缓存singletonFactories

第四,B需要注入A,通过三级缓存中获取ObjectFactory来生成一个A的对象,同时存入二级缓存,这个是有两种情况,一个是可能是A的普通对象,另外一个是A的代理对象,都可以让ObjectFactory来生产对应的对象,这也是三级缓存的关键

第五,B通过从通过二级缓存earlySingletonObjects 获得到A的对象后可以正常注入,B创建成功,存入一级缓存singletonObjects

第六,回到A对象初始化,因为B对象已经创建完成,则可以直接注入B,A创建成功存入一次缓存singletonObjects

第七,二级缓存中的临时对象A清除

三级缓存解决循环依赖的局限性

三级缓存只是解决了构造函数之后的循环依赖问题,那么构造函数的循环依赖问题怎么解决呢?

​ - Spring 给我们提供了一个 @Lazy 注解,也叫懒加载,或延迟加载。被这个注解修饰的对象,只有在使用的时候才会创建实例,那时单例池中的其他对象都已经创建好了,便解决了循环依赖的问题。

三级缓存机制只能解决单例Bean的循环依赖问题,对于原型(prototype)Bean的循环依赖无能为力