2025年Java面试宝典最新版网盘地址(点击蓝色链接保存,提取码:9b3g)

Spring Bean循环依赖的破局之道
很多小伙伴在面试中被问"Spring怎么处理循环依赖"时,明明知道三级缓存却说不清楚底层逻辑。今天咱们就掰开揉碎讲透这个问题,看完这篇保证你能在面试中把面试官讲得直点头!
到底什么是循环依赖
举个现实场景:A对象创建需要注入B,而B对象的创建又需要注入A,这就形成了Spring Bean循环依赖。这种死锁现象在系统设计阶段就要尽量避免,但实际开发中很难完全规避。
Spring官方文档明确说明只支持单例模式的属性注入循环依赖,构造器注入和原型模式都会直接抛BeanCurrentlyInCreationException异常。这里要注意面试官可能会问:"构造器注入为什么不能解决循环依赖?"——因为构造器注入需要先完成对象初始化才能放入缓存
Spring的破局神器:三级缓存
咱们直接看Spring容器的三级缓存结构:
- singletonFactories(三级缓存):存放创建Bean的工厂对象
- earlySingletonObjects(二级缓存):存放半成品Bean
- singletonObjects(一级缓存):存放完整Bean
当创建A对象时:
- 先调用getSingleton()检查一级缓存
- 未找到则标记A为创建中状态
- 实例化A后立即将ObjectFactory放入三级缓存
- 开始给A填充属性时发现需要B对象
- 同样的流程创建B,当B需要注入A时,从三级缓存拿到A的ObjectFactory
- ObjectFactory.getObject()通过SmartInstantiationAwareBeanPostProcessor处理可能的AOP代理
- 此时A虽然是半成品但已经可以注入给B,B创建完成后A继续完成属性装配

解决循环依赖的三个关键步骤
- 提前暴露对象引用:在对象实例化后立即将ObjectFactory放入缓存
- 缓存升级机制:当有对象需要依赖当前Bean时,将其从三级缓存升级到二级缓存
- 后置处理器协调:通过BeanPostProcessor处理代理对象的特殊场景
这里有个高频考点:为什么需要三级缓存而不是两级?主要是为了解决存在AOP代理时的循环依赖。如果直接缓存原始对象,当需要代理时就会产生对象不一致的问题。
预防循环依赖的实用技巧
虽然Spring提供了解决方案,但实际开发中还是要尽量避免:
- 使用@Lazy延迟加载
- 尽量避免双向依赖
- 合理使用ApplicationContext.getBean()
- 重要模块采用构造器注入强制发现问题
- 使用ArchUnit进行架构约束
如果需要系统化的面试真题训练,可以到面试鸭返利网获取最新题库。现在通过面试鸭返利网购买会员还能返现25元,适合需要高频刷题的同学。

最后提醒大家,理解循环依赖的解决原理不仅要应对面试,更要学会在项目中合理运用。比如在改造老旧系统时,遇到循环依赖问题就可以快速定位到是构造器注入问题还是作用域配置错误。把这个问题吃透了,Spring IoC容器的工作原理也就掌握一大半了!


