面向对象开发中的循环依赖解决:利用Setter注入与代理对象技巧

风伟吖_7694

风伟吖_7694

2026-05-20

608人浏览

原创

Spring通过三级缓存(singletonFactories、earlySingletonObjects、singletonObjects)支持单例Bean的setter注入循环依赖,先实例化后设值,允许提前暴露半成品对象;构造器注入因依赖必须前置而无法解决循环依赖,需配合@Lazy代理或重构设计。

面向对象开发中的循环依赖解决:利用setter注入与代理对象技巧

Spring 能解决单例 Bean 的循环依赖,关键在于它不靠“等对象完全造好再注入”,而是允许在对象刚实例化、还没完成属性赋值时,就提前暴露出来供其他 Bean 使用。Setter 注入和代理对象正是配合这一机制落地的两种实用手段。

为什么 Setter 注入能绕过循环依赖

构造器注入要求所有依赖在创建对象前就必须就位,一旦 A 依赖 B、B 又依赖 A,就会卡死在“谁先造”的死结里。而 Setter 注入把依赖关系拆成两步:先调用无参构造器生成空壳对象,再通过 set 方法填充依赖。这给了 Spring 缓冲空间——A 实例化后暂存起来,即使还没设 B,也能先被 B 拿去用;B 完成后再回头给 A 补上 B 的引用。

  • 必须是单例(prototype 不支持)
  • 两个 Bean 都要用 setter 或 @Autowired 标注在字段/方法上,不能混用构造器注入
  • Spring 内部靠三级缓存协作:A 刚 new 出来就放进三级缓存(ObjectFactory),B 查找 A 时从这里取,升级到二级缓存,最后 A 填完属性再进一级缓存

@Lazy 注解如何配合构造器注入破局

如果非要用构造器注入(比如强调不可变性),@Lazy 是最直接的补救方式。它不是延迟整个 Bean 的创建,而是延迟该依赖的解析时机——A 构造时并不立刻要一个真实的 B 实例,而是一个“将来才初始化的 B 代理”。等 A 真正调用 B 的方法时,B 才被创建,此时 A 已经在容器里了,B 就能顺利拿到 A。

  • 只对单例有效,且仅作用于被标注的依赖参数
  • 注意:@Lazy 加在字段或构造器参数上都行,但加在类上会影响整个 Bean 的加载时机
  • 副作用:调用被 @Lazy 的 Bean 时会有首次初始化开销,不适合高频短生命周期场景

代理对象在循环依赖中的真实角色

很多人误以为“用了 AOP 就没法循环依赖”,其实恰恰相反:Spring 的三级缓存中,第三级 singletonFactories 存的不是对象本身,而是一个 ObjectFactory,它的作用就是按需生成代理对象。当 A 和 B 循环依赖,且其中某个需要事务或切面增强时,Spring 会在这个工厂里提前准备好代理逻辑。B 拿到的不是原始 A,而是 A 的代理(可能已织入事务拦截器),但这个代理背后仍指向同一个早期 A 实例,保证了引用一致性。

  • 代理对象不是为解决循环依赖而生,但它是循环依赖能安全落地的前提
  • 如果 B 依赖的是 A 的代理(比如 A 加了 @Transactional),那 A 在三级缓存里暴露的就必须是能生成该代理的工厂,而不是裸对象
  • 手动使用 AopContext.currentProxy() 获取当前代理,在循环依赖场景下要格外小心线程与作用域

比技术更关键的设计提醒

Setter 注入和 @Lazy 是应急方案,不是设计常态。真正健康的代码结构,应该从源头减少耦合:

  • 用接口隔离依赖:A 依赖 IAction 接口,B 实现它,A 就不再和 B 类名强绑定
  • 引入中介者或事件机制:A 发布“任务开始”事件,B 订阅处理,双方不再持有对方引用
  • 检查是否真需要双向引用:B 持有 A 的 ID 或名称就够了,不一定非要持 A 实例
  • 把共用逻辑抽成独立 Service,让 A 和 B 都依赖它,打破闭环
PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

2023.06.15

11457

6

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

2023.07.05

8582

9

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

2023.07.31

7372

8

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.01

1224

3

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.02

988

3

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

1476

5

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

3009

5

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

2023.08.03

20271

3

配置java环境变量
配置java环境变量

配置Java环境变量是为了让操作系统能够识别和使用Java的相关命令和功能。本专题为大家提供配置java环境变量相关文章,帮助大家解决问题。

2023.08.03

1315

8

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.7万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 134.1万人学习