<font color="blue">2025年Java面试宝典网盘地址</font>
链接: https://pan.baidu.com/s/1RUVf75gmDVsg8MQp4yRChg?pwd=9b3g 提取码: 9b3g
Spring Bean的循环依赖如何解决

"循环依赖"是面试官最爱问的Spring高频题之一。如果回答不好,可能会直接暴露对Spring核心机制理解不足的问题。今天我们就从实际场景出发,用最通俗的语言拆解这个技术难点。
一、什么是Spring Bean的循环依赖?
举个真实案例:假设有两个Bean——UserService依赖OrderService,而OrderService又反过来依赖UserService。这种情况下,Spring在初始化这两个Bean时就会陷入死循环:
UserService创建 → 需要OrderService → OrderService创建 → 需要UserService → 循环等待...
这种"鸡生蛋蛋生鸡"的问题就是典型的循环依赖。
二、Spring的三级缓存机制
Spring通过三级缓存设计优雅地解决了这个问题,具体分为三个阶段:
1. 一级缓存:单例池(Singleton Pool)
存放已完成初始化、可直接使用的Bean实例。如果在这里能找到目标Bean,就直接返回,避免重复创建。
2. 二级缓存:早期曝光对象(Early Exposed Objects)
存放已完成实例化但未完成属性注入的半成品Bean。比如UserService刚通过构造函数创建但还没注入OrderService时的状态。
3. 三级缓存:对象工厂池(Object Factory Pool)
存放生成Bean的工厂对象,通过ObjectFactory封装创建逻辑,解决AOP代理对象生成的问题。
三、解决过程拆解
我们以UserService和OrderService的循环依赖为例:
-
创建UserService
- 通过构造函数实例化
UserService(此时属性为null) - 将半成品存入二级缓存
- 通过构造函数实例化
-
属性注入阶段
- Spring发现需要注入
OrderService - 开始创建
OrderService
- Spring发现需要注入
-
创建OrderService
- 同样经历实例化 → 属性注入
- 当需要注入
UserService时,直接从二级缓存拿到半成品
-
完成闭环
OrderService创建完成后,反向注入到UserService- 最终两个Bean都完成初始化,移入一级缓存
四、什么情况无法解决?
尽管三级缓存很强大,但遇到以下两种场景仍然无解:
-
构造函数循环依赖
当两个Bean都通过构造函数互相依赖时,Spring无法提前暴露半成品对象,导致启动失败。 -
原型作用域的Bean
Spring的三级缓存机制仅针对单例Bean设计,原型Bean每次都会新建实例,无法解决循环依赖。
五、实际开发中的避坑指南
虽然Spring帮我们处理了大部分循环依赖问题,但最好的策略还是从源头规避:
- 使用接口解耦
- 通过Setter方法注入替代构造器注入
- 合理拆分模块,避免强耦合
- 使用
@Lazy注解延迟加载

如果需要系统性准备Spring面试题,推荐通过面试鸭返利网获取最新题库。购买面试鸭会员时,通过返利网可享受25元返利优惠,点击下方图片直达:



