如何在Java中处理复杂的对象依赖关系_理解循环依赖的风险

千涛同学_1100

千涛同学_1100

2026-02-15

838人浏览

原创

Spring默认禁止构造器注入的循环依赖,因无法提前暴露实例;仅支持单例Bean在setter/字段注入下通过三级缓存解决,原型Bean及隐式依赖(如事件监听、@PostConstruct中getBean)仍会失败。

如何在java中处理复杂的对象依赖关系_理解循环依赖的风险

Spring 为什么默认禁止循环依赖

Spring 容器在单例 Bean 初始化过程中,会提前暴露一个“正在创建中”的 ObjectFactory 来应对循环依赖。但它只对「构造器注入」完全无解,仅支持「setter 或字段注入」场景下的三级缓存自救。

常见错误现象:BeanCurrentlyInCreationException 或启动时报 Requested bean is currently in creation;本质是 A 依赖 B、B 又在构造器里强依赖 A,Spring 连实例都还没 new 出来,根本没法塞进缓存。

  • 构造器注入 + 循环依赖 → 必然失败,Spring 不做任何尝试
  • 字段/Setter 注入 + 单例 + 非懒加载 → Spring 能靠 singletonObjects / earlySingletonObjects / singletonFactories 三级缓存兜住
  • 原型(@Scope("prototype"))Bean 出现循环依赖 → 直接抛异常,不走缓存逻辑

如何识别代码里藏着的隐式循环依赖

不是只有 A → B → A 才叫循环依赖。当存在继承、代理、事件监听或自动装配泛型时,依赖链可能被遮蔽。

典型场景:

  • 使用 @EventListener 订阅本类发布的事件 → 当前 Bean 尚未初始化完成,但事件机制已触发其方法调用
  • 通过 ApplicationContext.getBean(Xxx.class) 在 @PostConstruct 中手动获取另一个 Bean,而那个 Bean 又间接依赖当前类
  • Lombok 的 @RequiredArgsConstructor 自动生成构造器,若字段类型恰好形成闭环,编译期看不出,运行时报错

建议在 IDE 中右键查看 “Find Usages” 后逆向追踪依赖图,比光看 @Autowired 更可靠。

@Lazy 能不能一劳永逸解决循环依赖

加 @Lazy 是最常用的绕过手段,但它只是延迟初始化,并不消除依赖关系本身。

Java Api Extractor
Java Api Extractor

从 Java 项目中提取 Controller 层接口定义为 JSON 数据。

下载

要注意:

  • @Lazy 对构造器参数生效,但必须确保该 Bean 自身也是单例(否则每次 getBean 都新建,@Lazy 失效)
  • 与 @Async 或事务代理结合时,@Lazy 可能导致代理对象未正确织入,出现空指针或事务不生效
  • 测试环境下若用 Mockito.mock() 替换 Bean,@Lazy 会让 mock 行为失效——因为 Spring 拿到的是代理,不是原始 mock 实例

示例:如果 B 类有 @Lazy final A a;,那第一次调用 a.doSomething() 才触发 A 的创建,此时若 A 又依赖 C、C 又依赖 B,就又回到原问题。

真正该重构的不是配置,是职责边界

循环依赖往往暴露的是设计问题:两个类承担了不该耦合的职责,比如服务层直接操作数据源配置、监听器里混着业务逻辑、或者把策略选择和策略实现写死在同一处。

比起加 @Lazy 或拆成 setter,更值得花时间做的:

  • 把共享状态抽成独立的 @Service,让 A 和 B 都依赖它,而非彼此
  • 用 ApplicationEventPublisher 替代直接调用,把“执行时机”和“执行主体”解耦
  • 对复杂流程引入命令模式或状态机,避免服务类之间形成网状调用

Spring 的循环依赖支持是个补丁,不是设计指南。它能让你跑起来,但跑得久不久,取决于你有没有动过那几行真正该删掉的依赖。

Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

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

下载

相关标签:

java

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

相关专题

更多
spring框架介绍
spring框架介绍

本专题整合了spring框架相关内容,想了解更多详细内容,请阅读专题下面的文章。

2025.08.06

2791

22

Java Spring Security 与认证授权
Java Spring Security 与认证授权

本专题系统讲解 Java Spring Security 框架在认证与授权中的应用,涵盖用户身份验证、权限控制、JWT与OAuth2实现、跨站请求伪造(CSRF)防护、会话管理与安全漏洞防范。通过实际项目案例,帮助学习者掌握如何 使用 Spring Security 实现高安全性认证与授权机制,提升 Web 应用的安全性与用户数据保护。

2026.01.26

497

25

C++ 智能指针与现代内存管理
C++ 智能指针与现代内存管理

深入讲解 C++ 现代内存管理的核心工具——智能指针,涵盖 unique_ptr 独占所有权语义、shared_ptr 引用计数机制与循环引用问题、weak_ptr 弱引用的应用场景、make_unique/make_shared 工厂函数的性能优势、自定义删除器的编写、RAII 资源管理思想的实践,以及从裸指针迁移到智能指针的重构策略,帮助开发者编写安全无泄漏的现代 C++ 代码。

2026.04.23

379

31

class在c语言中的意思
class在c语言中的意思

在C语言中,"class" 是一个关键字,用于定义一个类。想了解更多class的相关内容,可以阅读本专题下面的文章。

2024.01.03

4276

7

python中class的含义
python中class的含义

本专题整合了python中class的相关内容,阅读专题下面的文章了解更多详细内容。

2025.12.06

306

9

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

2026.03.13

391

19

空指针异常处理
空指针异常处理

本专题整合了空指针异常解决方法,阅读专题下面的文章了解更多详细内容。

2025.11.16

179

10

Vite 项目如何打包和部署
Vite 项目如何打包和部署

Vite项目打包部署专题汇集生产构建、产物预览、输出目录、资源路径、Nginx与GitHub Pages部署及常见白屏和路由404问题的已审核文章,帮助读者完成上线流程。

2026.10.28

80

16

Vite 如何搭配 Vue.js
Vite 如何搭配 Vue.js

Vite搭配Vue.js专题汇集创建Vue 3项目、配置开发环境、路径别名、Vue插件、代理、多环境构建与调试的已审核文章,帮助读者完成从初始化到日常开发的配置。

2026.10.28

60

15

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习