spring三级缓存解决循环依赖问题

发布时间:2026/8/9 10:37:55
spring三级缓存解决循环依赖问题 spring三级缓存(解决循环依赖)什么是循环依赖多个 Bean 互相依赖对方形成闭环。//A依赖BComponentpublicclassA{AutowiredprivateBb;}//B依赖AComponentpublicclassB{AutowiredprivateAa;}A 需要 B 才能完成创建B 又需要 A 才能完成创建 → 循环依赖分类字段/setter注入(单例): spring可以通过三级缓存解决构造器注入: Spring 无法解决直接抛出BeanCurrentlyInCreationExceptionprototype 作用域 Bean完全不支持循环依赖为什么构造器注入的循环依赖不能解决构造器注入调用构造方法的时候就必须把依赖全部传入。ComponentpublicclassA{publicA(Bb){}}创建 A 的时候调用构造函数就必须拿到 B创建 B 又要 A。对象还没有实例化出来没有机会把半成品对象放入三级缓存直接卡死。setter / 字段注入流程先 new 对象实例化→ 对象已经存在放入三级缓存 → 再填充属性。 对象已经实例完成才有机会暴露半成品。三级缓存仅针对单例、setter / 字段注入构造器注入无法解决循环依赖。三级缓存都存于DefaultSingletonBeanRegistry类中。// 一级缓存完整实例化完成的单例BeanprivatefinalMapString,ObjectsingletonObjects;// 二级缓存实例化完成但还未填充属性、未初始化的原始Bean对象early‑referenceprivatefinalMapString,ObjectearlySingletonObjects;// 三级缓存Bean工厂对象用于生成Bean的早期代理对象privatefinalMapString,ObjectFactory?singletonFactories;各类缓存作用一级缓存 singletonObjects存放完全创建完毕实例化 属性填充 初始化的单例 Bean。作用Bean 最终成品仓库。获取逻辑获取 Bean 优先查一级缓存。如果在这里拿到对象直接返回流程结束。循环依赖过程中Bean 还没完成属性填充不会放入一级缓存。三级缓存 singletonFactories存放Object Factorylambda / 工厂回调不是 Bean 对象本身。对象实例化完成new 出来对象属性还没填充就把一个 lambda 工厂放入三级缓存。addSingletonFactory(beanName,()-getEarlyBeanReference(beanName,mbd,bean));核心作用用于在需要的时候生成该 Bean 的 AOP 代理对象。如果这个 Bean 需要 AOP 代理工厂会返回代理对象不需要代理直接返回原始对象。注意:不会立刻执行工厂方法只有别的 Bean 需要引用它的时候才执行工厂拿到对象。为什么要用工厂而不是直接放对象 不是所有 Bean 都发生循环依赖大部分 Bean 不需要提前代理。延迟执行代理逻辑节省性能。二级缓存 earlySingletonObjects存放已经调用三级工厂生成出来的早期对象原始对象 / 代理对象实例化完成但属性未填充作用缓存三级工厂执行后的结果避免重复执行代理逻辑。当从三级缓存执行 Object Factory 拿到对象之后就把对象放到二级缓存同时删除三级缓存中的 factory。后续其他 Bean 再依赖这个 Bean直接从二级缓存取不再重复执行代理。二级缓存解决同一个 Bean 被多个 Bean 循环引用时不要重复创建代理。完整三级缓存处理循环依赖流程A 依赖 BB 依赖 A1.创建 A实例化 new A 对象属性还没填充。把 A 的代理工厂放入三级缓存 singletonFactories。**2.**填充 A 的属性发现需要 B开始创建 B。3.创建 B实例化 new B 对象把 B 的代理工厂放入三级缓存。**4.**填充 B 的属性发现需要 A。尝试获取 A。​ 1.一级缓存无 A​ 2.查询三级缓存执行 A 的 ObjectFactory得到 A 的早期对象原始 / 代理​ 3.将 A 放入二级缓存 earlySingletonObjects删除三级缓存中的 A 工厂。5.B 拿到 A 早期对象完成 B 属性填充、初始化B 完成放入一级缓存 singletonObjects。6. ** A 拿到完整的 B 对象完成 A 属性填充、初始化A 完成放入一级缓存**删除二、三级缓存中 A 的记录。缓存存储内容核心作用一级 singleton Objects完整就绪的单例 Bean存放最终成品 Bean优先获取完整 Bean二级 earlySingleton Objects实例化完成、未填充属性的 Bean (原始 / 代理)保存三级工厂执行后的对象避免重复代理三级 singleton FactoriesObject Factory 对象工厂 (lambda)延迟生成 Bean 的早期代理对象只有被别人依赖才执行关键面试点1.如果没有 AOP 代理理论上二级缓存就可以解决循环依赖引入三级缓存是为了延迟 AOP 代理创建。 2.构造器注入无法解决对象还没有实例化根本没有机会放入三级缓存。 3.仅支持 scopesingletonprototype 多实例不支持循环依赖. 4.Bean 创建完成后二、三级缓存会清理只有一级缓存保留对象。Spring 必须靠三级缓存才能解决循环依赖吗结论不是。如果项目完全没有 AOP 代理只用【一级缓存 二级缓存】就可以解决循环依赖。 Spring 设置三级缓存singletonFactories是专门为处理 AOP 代理场景不是解决普通对象循环依赖的必需品。场景1: Bean 不需要 AOP 代理无 Transactional、无切面此时三级缓存里面的工厂执行直接返回原始对象。逻辑等价实例化完直接把原始对象放入二级缓存不需要工厂。这种场景两级缓存就足够解决循环依赖。场景2: Bean 需要 AOP 代理如加了 Transactional这是三级缓存存在的真正理由。Bean 刚实例化完成属性还没填充正常 AOP 代理是在初始化之后才创建。 但是发生循环依赖时别的 Bean 要提前引用这个 Bean此时必须提前生成代理对象。三级缓存存放的是回调工厂addSingletonFactory(beanName, () - getEarlyBeanReference(beanName, mbd, bean));getEarlyBeanReference()如果需要代理就提前生成代理不需要代理返回原对象。关键点工厂不会立刻执行。只有其他 Bean 需要引用这个 Bean触发循环依赖才执行工厂生成代理对象。如果没有发生循环依赖工厂永远不执行代理还是走正常流程初始化之后创建避免无谓提前代理提升性能。如果去掉三级缓存只保留一级 二级会发生什么方案实例化 Bean 之后直接生成代理对象放入二级缓存。功能上可以解决循环依赖但是性能有代价所有单例 Bean实例化完成之后不管会不会发生循环依赖全部提前创建代理对象。大部分 Bean 根本不会出现循环依赖白白提前做 AOP 代理浪费 CPU。Spring 设计者选择不提前生成代理把代理逻辑封装进 ObjectFactory延迟触发于是引入三级缓存。模拟流程只有一级 二级缓存、无 AOP可以正常解决循环依赖 A↔B1.new A实例化放入二级缓存2.A 填充属性发现需要 B → new B放入二级缓存3.B 填充属性发现需要 A从二级缓存拿到原始 A 对象4.B 填充属性、初始化完成移入一级缓存5.A 拿到 B填充属性初始化完成移入一级缓存整个流程正常跑完循环依赖解决。注意: 一旦有 AOP 代理两级缓存方案就有问题要么提前全部代理损耗性能要么拿不到代理对象。高频面试问答Q三级缓存是用来解决循环依赖的吗A不完全准确。真正用来 “拿到半成品对象打破闭环” 的是一、二级缓存三级缓存的核心目的是延迟 AOP 代理对象的创建兼顾性能和循环依赖场景。Q那为什么网上都说三级缓存解决循环依赖A因为 Spring 容器要同时兼容两种情况普通 Bean AOP 代理 Bean。在 Spring 完整源码实现中为了兼容 AOP最终使用了三级缓存这套整体方案。所以整体上说 Spring 靠三级缓存机制解决循环依赖但不能理解为 “没有三级缓存就一定不能解决循环依赖”。Q能不能自己写代码实现循环依赖只使用两级缓存A可以前提是你的业务不做 AOP 动态代理。一旦引入代理逻辑两级缓存就需要提前创建代理带来性能损耗。循环依赖方案对比方案对比两级缓存 vs 三级缓存对比维度两级缓存方案一级 二级无 AOPSpring 原生三级缓存方案缓存结构singletonObjects完整 Bean earlySingletonObjects早期对象singletonObjectsearlySingletonObjectssingletonFactories工厂回调三级缓存作用不存在存放ObjectFactorylambda 工厂延迟生成 AOP 代理对象能否解决普通 Bean 循环依赖✅ 可以✅ 可以能否解决带 AOP 代理的循环依赖❌ 不行要么拿不到代理要么全部提前代理✅ 可以工厂回调提前生成代理AOP 代理创建时机实例化后立即创建所有 Bean 都提前代理发生循环依赖被引用时才执行工厂创建代理无循环依赖则正常初始化后代理性能开销高所有单例 Bean 实例化后都提前做代理低只有真正发生循环依赖的 Bean 才提前代理代理对象是否唯一可能重复生成多份代理无工厂缓存二级缓存缓存工厂执行结果保证单例适用场景极简容器、无 AOP、无切面生产级完整 Spring 容器兼容 AOP / 事务 / 切面构造器注入能否解决❌ 不能❌ 不能与缓存级别无关prototype 作用域能否解决❌ 不能❌ 不能不进入缓存三级缓存各层职责速查表缓存名称类型存什么什么时候放入什么时候移除核心作用singletonObjects一级MapString, Object完整就绪的单例 BeanBean 创建全部完成后容器销毁时存放最终成品获取 Bean 优先查这里earlySingletonObjects二级MapString, Object实例化完成、未填充属性的早期对象原始 / 代理三级工厂执行后Bean 放入一级缓存时缓存工厂执行结果避免重复代理singletonFactories三级MapString, ObjectFactory?ObjectFactory 工厂回调Bean 实例化完成后工厂执行后 / Bean 放入一级缓存时延迟生成 AOP 代理只有被引用才执行

相关新闻