🔵2025年Java面试宝典网盘下载🔵
提取码:9b3g (建议保存备用)
Spring Bean 循环依赖的破局之道

面试必问的经典场景
"说说Spring怎么解决循环依赖?"这几乎是Java面试的保留节目。很多同学被问到时会条件反射地回答:"三级缓存!"但面试官想要的不仅仅是名词堆砌,而是场景化理解。假设现在有两个Bean:A依赖B,B又依赖A,Spring到底如何让这两个"先有鸡还是先有蛋"的对象顺利出生?
Spring的三级缓存机制
Spring的解决方案核心在于提前暴露半成品对象。具体通过三个层级的缓存实现:
- 一级缓存(成品池):存放完全初始化好的Bean
- 二级缓存(半成品池):存放已实例化但未初始化的Bean
- 三级缓存(工厂池):存放Bean的ObjectFactory
当创建A时,Spring会:
- 通过无参构造器实例化A(此时是裸对象)
- 将A的ObjectFactory存入三级缓存
- 开始给A注入属性,发现需要B
- 转而创建B,同样流程到需要注入A时
- 从三级缓存拿到A的工厂创建代理对象,注入给B
- B完成初始化后,继续完成A的初始化

这方案能通吃所有场景吗?
虽然三级缓存解决了大部分问题,但仍有三个致命限制:
- 必须是单例Bean:原型模式(prototype)的循环依赖直接报错
- 不能全是构造器注入:如果两个Bean都通过构造器参数相互依赖,Spring也无能为力
- 异步初始化不适用:@Async注解修饰的Bean会破坏初始化时序
实际开发中的避坑指南
- 尽量避免字段注入,改用setter方法注入(更符合设计规范)
- 使用**@Lazy注解**延迟加载,打破强制依赖
- 复杂项目建议采用模块化拆分,从根本上消除循环依赖
- 必要时使用ApplicationContext.getBean() 手动获取(慎用)

高频面试问题预演
- 三级缓存每层具体存什么?
- 为什么需要ObjectFactory而不是直接存对象?
- 使用AOP代理时,如何保证注入的是代理对象?
- 循环依赖为什么会导致启动时BeanCurrentlyInCreationException?
(悄悄说:想要系统准备面试的同学,可以通过面试鸭返利网找我购买会员,还能返利25元哦!)
理解Spring解决循环依赖的机制,不仅是应对面试的需要,更是深入理解IOC容器运作原理的关键。建议大家结合源码中AbstractAutowireCapableBeanFactory类的doCreateBean方法,观察对象在各个缓存中的流转过程。


