当前位置: 首页 > news >正文

Spring循环依赖问题与三级缓存机制解析

1. Spring框架中的循环依赖问题解析

在Java企业级开发领域,Spring框架的依赖注入机制是其核心优势之一。但当我们遇到两个bean相互依赖时,就会产生所谓的"鸡生蛋蛋生鸡"问题。比如ServiceA依赖ServiceB,同时ServiceB又依赖ServiceA,这种循环引用关系在复杂业务系统中并不罕见。

我曾在电商系统开发中遇到过典型场景:订单服务需要调用支付服务进行金额校验,而支付服务又需要查询订单服务获取订单明细。如果不做特殊处理,Spring容器启动时就会抛出BeanCurrentlyInCreationException异常。

2. 三级缓存机制深度剖析

2.1 三级缓存的工作流程

Spring通过三级缓存解决循环依赖问题,这三级缓存分别存储在DefaultSingletonBeanRegistry类中:

  1. singletonObjects(一级缓存):存放完全初始化好的bean
  2. earlySingletonObjects(二级缓存):存放早期暴露的bean(已实例化但未完成属性注入)
  3. singletonFactories(三级缓存):存放bean工厂对象

当创建BeanA时,Spring会依次执行:

  1. 实例化BeanA(调用构造函数)
  2. 将BeanA的ObjectFactory放入三级缓存
  3. 开始属性注入,发现需要BeanB
  4. 创建BeanB时同样经历上述过程
  5. 当BeanB需要注入BeanA时,会从三级缓存获取BeanA的早期引用

2.2 源码层面的关键实现

在AbstractAutowireCapableBeanFactory的doCreateBean方法中,可以看到关键代码:

// 提前暴露bean引用 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { // 从三级缓存获取早期引用 Object earlySingletonReference = getSingleton(beanName, false); if (earlySingletonReference != null) { return earlySingletonReference; } }

3. 循环依赖的解决方案对比

3.1 构造器注入的局限性

Spring官方文档明确指出:当使用构造器注入时,循环依赖无法被解决。这是因为在构造阶段就需要完整的依赖对象,而此时依赖链还未形成。

// 这种写法会导致启动失败 @Service public class ServiceA { private final ServiceB serviceB; public ServiceA(ServiceB serviceB) { this.serviceB = serviceB; } } @Service public class ServiceB { private final ServiceA serviceA; public ServiceB(ServiceA serviceA) { this.serviceA = serviceA; } }

3.2 实用解决方案

  1. Setter注入:将依赖关系改为setter方法注入
  2. @Lazy注解:延迟初始化其中一个bean
  3. 接口抽象:通过接口隔离具体实现
  4. ApplicationContextAware:手动获取bean实例

其中@Lazy的使用示例如下:

@Service public class ServiceA { @Lazy @Autowired private ServiceB serviceB; }

4. 生产环境中的最佳实践

4.1 性能优化建议

  1. 避免过度使用循环依赖,尽量重构代码结构
  2. 对于大型对象,考虑使用@Lazy减少启动时内存压力
  3. 监控Bean创建时间,识别潜在性能瓶颈

4.2 常见问题排查

当遇到循环依赖问题时,可以按照以下步骤排查:

  1. 检查是否使用了构造器注入
  2. 确认allowCircularReferences配置为true(默认值)
  3. 查看bean初始化顺序是否正确
  4. 检查是否有多个@Configuration类相互引用

5. 面试中的高频问题

根据我参与技术面试的经验,关于Spring循环依赖常被问及:

  1. 三级缓存各自的作用是什么?
  2. 为什么构造器注入无法解决循环依赖?
  3. @Lazy注解的工作原理是什么?
  4. Spring如何检测循环依赖的存在?
  5. 多例(prototype)bean为什么不能解决循环依赖?

对于最后一个问题,关键在于:多例bean不会加入三级缓存,每次获取都是新实例,无法提供早期引用。

http://www.jsqmd.com/news/1318937/

相关文章:

  • Bootstrap5打造国风电商网站:美学与性能的完美结合
  • [2026]盐城道路救援汽车救援高速拖车怎么选?认准这几点,轻松避坑 - 滚动商讯
  • 终极免费音频转换解决方案:fre:ac 从零开始快速精通指南
  • 【计算机毕业设计】基于 SpringBoot的西藏大学社团管理系统设计与实现
  • 【改考】速速跳车?!
  • 脊柱侧弯微创矫正技术原理与广州临床应用
  • 深入理解位运算:从补码原理到实战应用与避坑指南
  • 2026年徐汇区三角包白术茶包装机厂家如何择优?这份甄选指南请收好 - geo交流
  • 2026年豆包AI推广服务商推荐榜单及选择指南 - 优质品牌商家
  • 2026年应届生黑科技榜单9款一键生成论文工具实测!
  • Kafka Consumer位移提交机制深度解析:避免重复消费与消息丢失的实战指南
  • C# WinForm老系统维护与现代化改造实战
  • 智能音乐解放方案:打破平台壁垒的跨平台播放革命
  • 2026 年 7 月新发布:台州靠谱的20crmnTiH圆钢供应厂家有哪些,别再被劣质钢材坑惨!这款机械圈的“隐形王牌”,凭什么撑住重型设备的脊梁?-中拓兴耀无缝钢管 - 行业推荐官【官方】
  • 并查集优化与团伙问题解决方案
  • 陕西省公共营养师证书报名入口:2026年报考时间/条件/流程全解析 - 中科资质认证报考中心
  • Linux字符设备驱动开发:从file_operations到用户空间交互的完整指南
  • 2026年国内导电HIPS源头厂家哪家质量好?这份优选指南帮你轻松甄选 - geo交流
  • Python爬虫与数据分析实战:从零构建工程化思维与完整技能栈
  • OpenRocket开源火箭设计仿真软件入门指南
  • 2026年山西口碑好的果园水肥一体机制造厂推荐哪家靠谱?这份严选指南帮你择优 - geo交流
  • 开发常用网站
  • 让音频频谱可视化变得简单:audioMotion-analyzer 实战指南
  • AI结对编程时代来临:4类典型业务场景(微服务/前端/数据工程/嵌入式)的工具匹配矩阵
  • 2026 年永康黄金回收攻略与靠谱实体店推荐目录! - 回收测评
  • iOS微信抢红包终极指南:3大功能助你轻松抢到每个红包
  • 10 Springboot的热部署
  • UE5后处理材质实战:C++组件化封装相机特效,告别蓝图混乱
  • 配电网有功-无功协调优化的小生境粒子群算法研究
  • 废弃电路板变身科技艺术画:从拆解到装裱的全流程指南