当前位置: 首页 > news >正文

【Spring源码08】终极万字拆解:三级缓存如何完美解决Bean循环依赖(面试压轴必刷)

🔥Spring源码全套连载系列(持续更新)

上一篇我们彻底吃透了Bean完整生命周期,明确了一个核心关键节点:

Bean在实例化阶段,就会提前曝光半成品对象,为解决循环依赖做铺垫

今天我们攻克Spring源码最难、最绕、面试压轴必考的终极难点:Bean循环依赖与三级缓存原理

90%的程序员只会背:一级存成品、二级存半成品、三级存工厂

但一问深层原理就彻底懵:

  • 循环依赖到底发生在Bean生命周期的哪一步?

  • 为什么一定要三级缓存?两级缓存能不能解决问题?

  • 三级缓存存的ObjectFactory工厂到底有什么用?

  • 为什么构造方法循环依赖无法解决?

  • AOP代理后的Bean,循环依赖是如何保证对象一致性的?

本篇摒弃废话、纯源码落地,逐行拆解三级缓存执行流程,彻底终结循环依赖所有疑问,看完直接吊打99%面试者!

一、前置认知:什么是Spring循环依赖?

1.1 定义与场景

循环依赖:两个或多个Bean之间互相依赖对方,形成闭环依赖关系。

日常开发最常见的场景:属性注入循环依赖

@Service public class AService { @Autowired private BService bService; } @Service public class BService { @Autowired private AService aService; }

A依赖B,B又依赖A,形成闭环,这就是经典循环依赖

1.2 三种循环依赖类型(重点)

Spring循环依赖分三种,只有一种能解决、一种无解、一种部分解决

  • 1. 属性注入循环依赖(setter/@Autowired)完全解决(三级缓存核心场景)

  • 2. 构造方法循环依赖完全无法解决(面试高频)

  • 3. 多例Bean循环依赖无法解决

本篇核心拆解:单例Bean属性注入循环依赖的底层解决方案。

1.3 核心疑问:为什么会出现循环依赖报错?

结合Bean生命周期理解:

正常Bean流程:实例化 -> 属性填充 -> 初始化 -> 存入单例池

如果没有三级缓存:

  1. 创建A,实例化完成,属性填充阶段需要B

  2. B未创建,开始创建B,B实例化完成,属性填充需要A

  3. 此时A还未完成创建、未存入单例池,容器找不到A

  4. 循环等待,最终抛出BeanCurrentlyInCreationException循环依赖异常

核心矛盾:半成品Bean无法被提前获取,导致互相依赖卡死。

二、Spring三级缓存核心结构(源码级)

Spring解决循环依赖的核心,就是DefaultSingletonBeanRegistry中的三个Map缓存,各司其职、层层兜底。

先熟记三级缓存源码定义,这是所有原理的基础:

// 一级缓存:存放【完全初始化完成、可直接使用】的单例Bean private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(); // 二级缓存:存放【实例化完成、未属性填充、未初始化】的半成品Bean(原始Bean/代理Bean) private final Map<String, Object> earlySingletonObjects = new HashMap<>(); // 三级缓存:存放【Bean工厂对象ObjectFactory】,用于提前生成Bean引用、创建代理 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();

2.1 三级缓存逐一级详解(必背)

① 一级缓存 singletonObjects

作用:存储完全成熟、初始化完毕、可直接对外使用的单例Bean。

时机:Bean完成初始化、AOP代理增强后,最终存入。

特点:全局唯一成品Bean,项目运行全程复用。

② 二级缓存 earlySingletonObjects

作用:存储半成品Bean(实例化完成,未完成属性填充和初始化)。

时机:从三级缓存获取Bean后,升级存入二级缓存,避免重复创建。

核心价值:解决多Bean互相依赖同一个半成品Bean的重复创建问题。

③ 三级缓存 singletonFactories

重中之重、最难理解的一级

存储内容:不是Bean对象,是ObjectFactory<?> 匿名工厂对象

核心作用提前曝光Bean引用,支持提前生成AOP代理对象

这也是为什么不能只用两级缓存,必须要有三级缓存的核心原因!

三、完整循环依赖执行流程(逐步骤还原)

AService、BService互相依赖为例,全程还原三级缓存执行链路,无任何跳跃步骤。

前置规则:Spring容器默认单例、非懒加载、允许循环依赖

步骤1:容器创建AService

  1. 根据BeanDefinition,通过反射实例化A原生空对象(此时属性全为空)

  2. 标记A为正在创建中(inCreation)

  3. 核心操作:将A的ObjectFactory工厂存入三级缓存 singletonFactories

  4. 进入A的属性填充阶段,发现需要依赖BService

步骤2:容器创建BService

  1. 容器未找到B,开始实例化B原生空对象

  2. 标记B为正在创建中,B的工厂存入三级缓存

  3. 进入B的属性填充阶段,发现需要依赖AService

步骤3:B尝试获取A,触发三级缓存查询

容器获取Bean的查询顺序是固定优先级一级 → 二级 → 三级

  1. 查一级缓存:A未创建完成,无数据

  2. 查二级缓存:A未升级,无数据

  3. 查三级缓存:找到A的ObjectFactory工厂

  4. 执行工厂getObject()方法,获取A的引用(如需AOP则提前创建代理)

  5. 缓存升级:将A半成品存入二级缓存,同时删除三级缓存中的A工厂

步骤4:B完成创建

  1. B成功获取到A的半成品对象,完成属性填充

  2. B执行初始化、后置处理、AOP代理

  3. B完全创建完成,存入一级缓存

步骤5:A完成剩余创建流程

  1. A成功获取到完整的B对象,完成属性填充

  2. A执行初始化、后置处理、AOP代理

  3. A创建完成,从二级缓存取出,存入一级缓存

  4. 清空二、三级缓存中A的临时数据

至此,循环依赖完美解决,无异常、对象完全一致

四、终极灵魂拷问:为什么两级缓存不行?

这是面试最高频、最难答的压轴题,90%开发者答不到核心点!

4.1 假设只有一级+二级缓存

二级缓存只能存储固定的半成品Bean对象

如果Bean需要AOP动态代理,会出现致命问题:

  • 二级缓存提前曝光的是原生裸对象

  • 最终存入一级缓存的是代理对象

  • 出现两个不同的Bean对象:依赖注入的是原生对象,容器最终使用的是代理对象

  • 导致事务、AOP切面失效,程序严重bug!

4.2 三级缓存的不可替代性

三级缓存存储的是ObjectFactory工厂,具备动态执行能力

当其他Bean依赖当前Bean时:

  1. 工厂实时判断当前Bean是否需要AOP代理

  2. 需要代理则提前生成代理对象进行曝光

  3. 不需要代理则直接曝光原生对象

  4. 保证:提前曝光的对象 = 最终存入单例池的对象

终极结论

两级缓存只能解决普通Bean循环依赖,无法解决AOP代理Bean的循环依赖;三级缓存是为了保证代理对象一致性而生!

五、为什么构造方法循环依赖无法解决?

很多人死记硬背:构造循环依赖无解。今天从源码层面彻底讲透!

5.1 三级缓存的存入时机

三级缓存工厂的存入时机:Bean实例化完成之后、属性填充之前

核心源码位置:doCreateBean()方法中addSingletonFactory()

5.2 构造注入的执行逻辑

构造方法注入:必须先传参依赖,才能完成实例化

执行顺序:

  1. 创建A,需要通过构造方法注入B

  2. 还未完成A的实例化,无法进入三级缓存存入阶段

  3. 创建B,构造方法需要注入A

  4. A未实例化、无三级缓存、无任何曝光渠道

  5. 彻底卡死,直接抛出循环依赖异常

一句话总结构造注入先依赖、后实例化;三级缓存需要先实例化、后曝光,时机完全冲突,因此无解!

六、多例Bean为什么无法解决循环依赖?

因为Spring不缓存多例Bean

  • 多例Bean每次获取都会新建对象,不存入一、二、三级缓存

  • 无法提前曝光半成品对象

  • 互相依赖时无限创建新对象,最终栈溢出报错

七、三级缓存执行优先级&缓存流转机制

7.1 Bean获取优先级(固定)

一级缓存(成品) > 二级缓存(半成品) > 三级缓存(工厂)

7.2 完整缓存流转链路

三级缓存 → 执行工厂getObject() → 升级存入二级缓存 → Bean创建完成 → 升级存入一级缓存 → 清空临时缓存

缓存设计精髓:三级是工具、二级是过渡、一级是最终归宿。

八、面试满分题库(本篇压轴必背)

1、Spring三级缓存分别是什么?作用是什么?

一级缓存singletonObjects存储完全初始化完成的成品单例Bean;二级缓存earlySingletonObjects存储实例化完成、未初始化的半成品Bean,避免重复创建;三级缓存singletonFactories存储Bean工厂对象,用于提前曝光Bean引用,支持AOP代理Bean的循环依赖,保证对象一致性。

2、为什么需要三级缓存?两级缓存不行吗?

两级缓存无法解决AOP代理Bean的循环依赖问题。二级缓存直接存储固定半成品对象,会导致依赖注入的原生对象和最终容器的代理对象不一致,造成AOP、事务失效。三级缓存通过工厂函数动态获取对象,可提前生成代理对象,保证提前曝光对象与最终成品对象完全一致。

3、构造方法循环依赖为什么无法解决?

三级缓存的存入时机是Bean实例化完成之后,而构造方法注入需要先依赖、后实例化,执行时机冲突,无法提前曝光半成品Bean,因此无法解决循环依赖。

4、Spring能解决哪些循环依赖?

仅能解决单例Bean、属性注入(@Autowired/setter)的循环依赖;构造方法循环依赖、多例Bean循环依赖均无法解决。

5、循环依赖的核心解决思想是什么?

利用三级缓存提前曝光半成品Bean引用,在Bean未完全创建完成时,提前对外提供对象引用,打破循环等待闭环,同时通过工厂机制保证代理对象一致性。

九、本篇总结&下期预告

本篇总结

本篇彻底击穿了Spring源码最难的三级缓存与循环依赖核心难点,彻底告别死记硬背:

  • 掌握三种循环依赖的可解性差异

  • 吃透三级缓存各自的职责、存储内容、流转机制

  • 深度理解三级缓存不可替代的核心原因(AOP代理一致性)

  • 弄懂构造、多例循环依赖无解的底层本质

  • 梳理完整循环依赖执行链路,适配所有面试场景

下期预告

下一篇我们开启Spring AOP源码深度拆解!从动态代理、切面匹配、拦截链路、事务AOP生效原理全方位解析,搞定Spring AOP核心底层!

💡 往期推荐 & 系列连载

本系列持续更新,全程干货无水文,关注我,带你从零吃透Spring源码,彻底搞定面试底层原理!

http://www.jsqmd.com/news/936787/

相关文章:

  • 循环综合案例(break和continue的学习)
  • 个税app截图生成器,模拟器带计算UI,php纯源码可以带源码
  • 8大网盘直链解析终极指南:如何免费实现高速下载的完整教程
  • 英雄联盟智能辅助工具League Akari:如何用开源技术提升你的游戏体验?
  • 福满多黄金回收+各区服务+上门回收|宁波正规黄金回收门店测评 - 余生黄金回收
  • 2026北京靠谱搬家公司排行榜,实测筛选高口碑优质服务商 - 极欧测评
  • 基于树莓派与多传感器的智能信箱DIY:从硬件选型到Web服务全链路实践
  • 扬州静奢风全屋定制2026,不喧嚣不网红这4家高定品牌最懂 - 高定
  • 终极微信聊天记录导出方案:免费高效备份你的数字记忆
  • 携程任我行卡怎么回收?三种渠道全解析 - 圆圆收
  • 告别服务器运维!用uniCloud云函数5分钟搞定你的第一个API接口
  • Linux下普通用户如何提权(sudo)
  • 基于Kenji-X1与振动探头的远程设备健康监测实践
  • 2026年北京工业消杀与餐饮虫害防治深度指南:如何选择真正的专业PCO服务商 - 优质企业观察收录
  • 南充黄金回收白银铂金彩金钻戒回收门店优选+2026年6月最新黄金回收TOP5实测排行榜及联系方式 - 速递信息
  • 【踩坑记录】UTF-8 和 GBK 编码冲突导致代码全变?Git 为什么没有提示冲突?
  • 垃圾回收算法有哪些区别,复制与标记整理怎么选
  • 从星历到轨道:一份给航天新人的六根数计算保姆级教程(附Python实现)
  • 2026年福州本地化优选,行业头部梯队名单出炉 - 速递信息
  • 光伏智能垃圾桶选购指南:如何科学挑选靠谱产品 - 资讯快报
  • 2026深圳美国物流专线服务商深度测评:10强榜单与合规稳时效选型 - 资讯速览
  • 5分钟免费搞定PotPlayer字幕翻译:百度翻译插件完全指南
  • 2026年进出口报关公司哪家好?行业服务能力深度解析 - 品牌排行榜
  • 2026 天津高端名表回收测评|劳力士、百达翡丽、宝玑变现避坑指南 - 合扬奢侈品交易中心
  • 微信3大自动回复,解放双手还能提升成交率
  • 基于PI控制器的RC遥控车牵引力控制系统设计与实现
  • 装修后除醛该优先选哪类?2026 十款除甲醛产品实测横评排行 - 资讯焦点
  • 工程铝板采购不踩坑:从工艺产能看穿优质厂家核心实力 - 深度智识库
  • LED净化平板灯推荐:10年行业老师傅私藏的这家靠谱源头工厂(2026年6月最新) - 商业新知
  • 成本降低30%!GPON OLT厂家真实项目案例解析 - 资讯快报