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

【Spring】三级缓存与循环依赖:面试高频考点全解析

前言

本篇针对Spring 三级缓存与循环依赖,将其面试题高频考点全解析。


一、什么是循环依赖?

答:循环依赖指两个或多个 Bean 之间相互依赖形成闭环。例如双向依赖,A 的属性需要注入 B,B 的属性需要注入 A;

<!-- 一种双向循环情况--><beanclass="com.pojo.Eraser"id="eraser"autowire="byName"><constructor-argref="pencil"/></bean><beanclass="com.pojo.Pencil"id="pencil"autowire="byName"><constructor-argref="eraser"/></bean>

二、Spring 如何解决循环依赖?

答:需要满足两个条件:1.必须是单例,原因是只有单例才能存入到三级缓存中;2.必须是setter注入。
核心是依赖三级缓存,这三级缓存定义在DefaultSingletonBeanRegistry中,本质是三个 Map。

缓存名称作用
一级缓存存储完全初始化完成的单例 Bean(可直接使用)
二级缓存存储未完全初始化但已提前暴露的单例 Bean 早期引用
三级缓存存储生成 Bean 早期引用的工厂对象

接下来必讲三级缓存解决循环依赖的完整流程!

三、三级缓存解决循环依赖的完整流程

答:以双向依赖为例,以下是完整流程。
1.实例化A(调用 A 的无参构造)。
2.暴露A 的工厂:为A创建工厂对象,并将该工厂存入三级缓存。
3.注入 A 的属性(调用A的setB方法):找一->二->三级缓存,但是没有找到b的实例,于是…
4.实例化B(调用B的无参构造)
5.暴露B的工厂:为B创建工厂对象,并将该工厂存入三级缓存。
6.注入B的属性(调用B的setA方法):找一->二->三级缓存,找到了A的工厂对象!于是成 A 的早期引用,为了避免重复生,再将A 的早期引用迁移到二级缓存,而B形成完整的bean放入一级缓存
7.现在回到了A的属性注入,找一级缓存直接找到了B的实例,注入成功!A形成完整的bean放入一级缓存

四、为什么需要三级缓存?两级不够吗?

答:支持 AOP 代理场景下的循环依赖。若只有两级缓存:Bean 实例化后需直接暴露早期引用到二级缓存。但如果 Bean 需要 AOP 代理,暴露的会是原始对象,而最终需要的是代理对象,导致注入的对象与最终 Bean 不一致。其价值是:只有当发生循环依赖时,才会调用工厂生成代理对象(或原始对象),确保注入的是最终需要的实例(代理或原始),同时避免提前生成代理破坏 Bean 的生命周期(代理逻辑应在初始化后执行)。


总结

1.循环依赖是 Bean 间相互依赖形成的闭环,会导致初始化失败。
2.Spring 通过三级缓存解决单例 Bean 的字段注入循环依赖,三级缓存分别存储成品 Bean、早期引用、生成早期引用的工厂。
3.核心流程是 “实例化→暴露工厂→查找依赖→提前引用→完成初始化”。
4.三级缓存的关键是支持 AOP 代理场景,避免注入对象与最终 Bean 不一致。

如有疑问或漏洞,欢迎指出!感谢浏览~

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

相关文章:

  • 智能视觉组竞赛全解析:从车模设计到OpenART mini视觉识别实战
  • Matlab坐标轴刻度科学计数法:10的次方显示优化技巧
  • DXVK信号量超时处理终极指南:彻底避免死锁问题
  • 强化学习基本概念
  • 【Vocoder】HiFi-GAN:高效高保真语音合成的GAN架构解析
  • 编辑器使用规则
  • libSQL性能测试终极指南:从压力测试到基准对比的完整实践方案
  • uniapp:鸿蒙报错> hvigor ERROR: Failed :entry:default@MergeProfile... > hvigor ERROR: The compatibleSdkVe
  • 深入理解Python Web框架:gh_mirrors/we/web_develop项目中的Flask应用案例
  • 第二周周二 - f
  • 终极代码质量检查指南:如何使用avante.nvim提升开发效率
  • 9篇7章17节:特殊的NHANES数据解读,包括NNYFS、NHEFS、NHES 和 HHANES 等数据
  • 如何使用nsync实现高效互斥锁(mutex):C语言并发编程实战指南
  • Quarkus缓存策略终极指南:Infinispan分布式缓存集成与实战
  • uniapp安卓苹果APP端:解决安卓/苹果IOS获取蓝牙ID不一致问题,获取到的deviceId不一致?uniapp蓝牙设备ios与安卓端deviceId不一致问题(ios和安卓的获取方式不一样)
  • 如何使用 JetBrains Mono 字体优化哈萨克语西里尔字符编码体验:开发者必备的免费等宽字体指南
  • 如何安全配置Thread脚本:保护你的京东账户与隐私指南
  • 如何利用Quarkus虚拟线程提升Java应用性能:Project Loom完整指南
  • 从卡顿到丝滑:独立开发者用Tracy优化游戏性能的实战手记
  • Dust终极性能优化指南:如何让磁盘扫描速度提升50%
  • CoreControl核心功能详解:从服务器管理到应用监控的完整解决方案
  • RAG-Anything终极指南:如何快速构建多模态智能检索系统
  • 从开发到发布:Snapcraft完整工作流指南
  • 终极指南:Tracy性能分析器如何通过网络协议确保采样数据完整性传输
  • Sinatra终极指南:揭秘Ruby最精简Web框架的DSL革命
  • 如何用onnx-modifier删除节点?两种高效删除模式全解析
  • 终极Tracy跨编译器支持指南:GCC/Clang/MSVC兼容性处理技巧
  • Pyroscope时序数据压缩终极指南:10倍存储效率提升秘籍
  • Phobos单元测试最佳实践:确保D语言标准库代码质量的关键步骤
  • Guice Grapher终极指南:快速掌握依赖关系可视化的10个技巧