Spring的三级缓存

spring中的循环引用的解决(三级缓存)

在创建A对象的同时需要使用B对象,在创建B对象的同时需要使用A对象

循环依赖循环依赖其实就是循环引用,也就是两个或两个以上的bean互相持有对方,最终形成闭环。

循环依赖在spring允许存在的,spring架构依据三级缓存已经解决了大部分的循环依赖

缓存名称 源码名称 作用
一级缓存 singletonObjects 单例池,缓存已经经历了完整的生命周期,已经初始化完成的 bean 对象
二级缓存 earlySingletonObjects 缓存早期的 bean 对象(生命周期还没走完)
三级缓存 singletonFactories 缓存的是 ObjectFactory,表示对象工厂,用来创建某个对象的
CreatingSet - DefaultSingletonBeanRegistry 中的一个 Set,用于记录 “正在创建中的 bean”,防止循环依赖检测时重复创建,确保循环依赖的 bean 能被正确识别和处理。
earlyProxyReferences - 当 bean 提前进行 AOP 代理时,会将代理对象暂存到该缓存,避免后续重复代理

image-20251028101301591

当 AService 存在循环依赖(依赖 BService,BService 又依赖 AService)时,其 bean 生命周期的执行逻辑如下:

1. AService 初始化阶段

  • 首先将 AService 加入 creatingSet标记其处于创建中
  • AService 进行实例化,生成普通对象后,将其对应的 ObjectFactory(逻辑为 () -> getEarlyBeanReference(beanName, mbd, bean))存入三级缓存 singletonFactories
  • 开始填充 AService 的依赖 BService(因 BService 是单例,触发 BService 的生命周期)。

2. BService 生命周期阶段

  • 实例化:生成 BService 的普通对象。
  • 处理循环依赖:填充 BService 依赖的 AService 时,从 creatingSet 识别出循环依赖,于是从 singletonFactories 中获取 AServiceObjectFactory,执行逻辑生成 AService 的 AOP 代理对象,并存入二级缓存 earlySingletonObjects,同时将 AServicesingletonFactories 中移除。
  • 填充其他属性:完成 BService 其他属性的填充。
  • 其他步骤(含 AOP):执行 BService 自身的 AOP 等逻辑。
  • 加入单例池:将 BService 加入一级缓存 singletonObjects,并从 creatingSet 中移除。

3. 填充 AService 的 CService 依赖(若有)

  • 开始填充 AService 的依赖 CService(因 CService 是单例,触发 CService 的生命周期)。

4. CService 生命周期阶段

  • 实例化:生成 CService 的普通对象。
  • 处理循环依赖(若涉及):若 CService 也依赖 AService,则从 creatingSet 识别循环依赖后,从 earlySingletonObjects 中获取 AService 的代理对象。
  • 其他步骤(含 AOP):执行 CService 自身的 AOP 等逻辑。
  • 加入单例池:将 CService 加入一级缓存 singletonObjects,并从 creatingSet 中移除。

5. AService 后续阶段

  • 填充其他属性:完成 AService 剩余属性的填充
  • AOP 代理与缓存处理:执行 AService 自身的 AOP 逻辑,若提前进行了 AOP 代理,会将代理对象与 earlyProxyReferences 进行关联判断。
  • 加入单例池:从 earlySingletonObjects获取 AService 的代理对象(或普通对象,若未提前代理),加入一级缓存 singletonObjects,并从 creatingSetearlySingletonObjects 中移除

image-20251028102323550

BService 创建时依赖的 AService 代理对象,其背后的普通对象确实是 “不完整的”,但:

  1. 代理对象仅持有引用,不触发实际调用;
  2. AService 会在后续流程中补全属性和初始化
  3. 业务调用发生在容器初始化完成后,此时对象已完整。

这正是 Spring 三级缓存设计的巧妙之处:通过 “提前暴露引用 + 延迟实际调用”,在保证单例和 AOP 正确性的前提下,解决了循环依赖问题。

posted @ 2025-10-28 11:42  Leo0OO  阅读(14)  评论(0)    收藏  举报