核心是确认代理对象是否被正确创建并注入:循环依赖导致spring提前暴露半成品,可能为未增强原始对象;需查日志、验类名、判advised接口、用@dependson或禁用循环依赖定位。

排查依赖注入循环导致的 AOP 失效,核心是确认代理对象是否被正确创建并注入——循环依赖会让 Spring 提前暴露一个“半成品”代理,而这个代理可能尚未完成 AOP 增强,或者被错误地替换成原始对象。
看日志里有没有 “Creating shared instance of singleton bean” 或 “Returning cached instance”
Spring 启动时会打印 Bean 创建和代理生成的关键日志。重点关注:
- 是否存在类似 “Creating AOP proxy for bean 'xxxService'” 的日志 → 说明代理已生成
- 是否存在 “Returning eagerly cached instance” 或 “Resolving circular reference” → 表明 Spring 正在用三级缓存处理循环依赖,此时暴露的可能是未增强的原始对象或早期代理
- 对比两个循环 Bean 的日志顺序:如果 A 依赖 B、B 又依赖 A,但 A 的代理日志出现在 B 的初始化之后,那 B 注入的很可能是 A 的原始实例(无 AOP)
检查注入点的实际类型是不是代理类
在运行时验证某个被注入的 Bean 是否真是代理对象:
- 打印其真实类名:bean.getClass().getName()
• 正常代理:如
com.example.UserService$$EnhancerBySpringCGLIB$$a1b2c3d4或$Proxy123• 失效风险:直接显示com.example.UserServiceImpl(原始类名)→ 说明没走代理 - 用 Advised.class.isAssignableFrom(bean.getClass()) 判断是否实现了 Spring 的
Advised接口(代理对象都实现它)
用 @DependsOn 拆解隐式循环依赖
有些循环不是直接的 @Autowired,而是通过 @PostConstruct、@Scheduled 或事件监听间接触发的。例如:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- A 类有
@Scheduled方法,内部调用了 B - B 类构造器或
@PostConstruct中又调用了 A 的方法 - 此时 Spring 可能因初始化顺序混乱,跳过对某一方的代理增强
- 解决:在 A 上加
@DependsOn("bBean"),强制 B 先完全初始化;或把定时逻辑移到独立的 Scheduler 类中
临时禁用循环依赖支持来暴露问题
在 application.properties 中加:
spring.main.allow-circular-references=false
启动失败时抛出的异常会明确指出哪两个 Bean 构成循环,以及它们各自的依赖路径。这是最直接的定位方式。修复后可再开启(默认为 true),但建议长期避免循环设计。
不复杂但容易忽略:循环依赖本身不是 bug,但当它和 AOP 结合时,会放大代理时机的不确定性。重点不是“怎么绕过”,而是“让代理在注入前就准备好”。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










