【Spring】Spring如何解决Bean的循环依赖 - 全面解析

📅 2026/7/31 21:27:58
【Spring】Spring如何解决Bean的循环依赖 - 全面解析
Spring如何解决Bean的循环依赖 - 全面解析1. 什么是循环依赖循环依赖是指两个或多个Bean之间相互依赖形成闭环依赖关系Spring容器在创建Bean过程中会出现依赖死锁问题。Spring中单例Bean、属性注入场景可通过机制解决部分循环依赖部分场景无法解决。循环依赖的三种场景场景1双向直接循环依赖最常见ComponentpublicclassBeanA{AutowiredprivateBeanBbeanB;}ComponentpublicclassBeanB{AutowiredprivateBeanAbeanA;}场景2多Bean间接循环依赖ComponentpublicclassServiceA{AutowiredprivateServiceBserviceB;}ComponentpublicclassServiceB{AutowiredprivateServiceCserviceC;}ComponentpublicclassServiceC{AutowiredprivateServiceAserviceA;}场景3Bean自我依赖特殊场景ComponentpublicclassSelfDependentBean{// 自身依赖自身普通场景无问题代理场景会触发循环依赖校验AutowiredprivateSelfDependentBeanself;}2. Spring解决循环依赖的核心机制Spring 核心通过三级缓存机制解决单例Bean、属性/Setter注入场景下的循环依赖核心思想提前暴露未完全初始化的Bean早期引用打破依赖闭环。三级缓存底层源码结构publicclassDefaultSingletonBeanRegistryextendsSimpleAliasRegistryimplementsSingletonBeanRegistry{// 一级缓存完整初始化完毕的单例Bean可直接使用privatefinalMapString,ObjectsingletonObjectsnewConcurrentHashMap(256);// 二级缓存早期Bean引用已实例化、未填充属性、未初始化privatefinalMapString,ObjectearlySingletonObjectsnewConcurrentHashMap(16);// 三级缓存Bean工厂对象用于生成早期引用、处理AOP代理privatefinalMapString,ObjectFactory?singletonFactoriesnewHashMap(16);// 标记正在创建中的Bean用于循环依赖预判privatefinalSetStringsingletonsCurrentlyInCreationCollections.newSetFromMap(newConcurrentHashMap(16));}三级缓存核心作用总结一级缓存singletonObjects存储完全初始化、属性填充完毕、可直接使用的单例Bean全局唯一。二级缓存earlySingletonObjects缓存早期Bean实例/代理对象避免重复执行三级缓存的代理创建逻辑提升性能。三级缓存singletonFactories核心关键存储Bean的ObjectFactory工厂可动态返回原始Bean或AOP代理Bean保证依赖注入一致性。3. 循环依赖完整解决流程详解以BeanA、BeanB双向循环依赖为例完整还原Spring容器创建、缓存流转、依赖注入全过程。测试案例代码ComponentpublicclassBeanA{AutowiredprivateBeanBbeanB;publicBeanA(){System.out.println(BeanA 构造函数执行);}PostConstructpublicvoidinit(){System.out.println(BeanA PostConstruct 执行);}}ComponentpublicclassBeanB{AutowiredprivateBeanAbeanA;publicBeanB(){System.out.println(BeanB 构造函数执行);}PostConstructpublicvoidinit(){System.out.println(BeanB PostConstruct 执行);}}分步执行流程步骤1容器启动开始创建BeanA将BeanA标记为「正在创建」步骤2执行BeanA构造函数完成实例化空对象无属性步骤3将BeanA的ObjectFactory存入三级缓存提前暴露早期引用支持后续依赖获取、AOP代理步骤4进入属性填充阶段检测到BeanA依赖BeanB触发BeanB创建步骤5标记BeanB为「正在创建」执行构造函数完成实例化步骤6将BeanB的ObjectFactory存入三级缓存步骤7填充BeanB属性检测到依赖BeanA步骤8从缓存获取BeanA一级缓存无、二级缓存无从三级缓存获取ObjectFactory生成BeanA早期引用步骤9将BeanA早期引用存入二级缓存删除三级缓存对应数据步骤10BeanB成功注入BeanA早期引用完成属性填充、PostConstruct初始化步骤11BeanB完全创建完成存入一级缓存清空二、三级缓存数据步骤12BeanA成功注入完整的BeanB实例完成自身属性填充、初始化步骤13BeanA创建完成存入一级缓存清空对应缓存数据循环依赖彻底解决核心流程源码模拟publicclassCircularDependencySimulator{// 模拟Spring三级缓存privateMapString,ObjectsingletonObjectsnewHashMapgt();// 一级缓存privateMapString,ObjectearlySingletonObjectsnewHashMap();// 二级缓存privateMapString,ObjectFactorysingletonFactoriesnewHashMap();// 三级缓存privateSetStringsingletonsInCreationnewHashSet();// 创建中Bean标记publicObjectgetBean(StringbeanName){// 1. 优先从一级缓存获取完整BeanObjectbeansingletonObjects.get(beanName);if(bean!null){returnbean;}// 2. 判断是否存在循环依赖Bean正在创建中if(singletonsInCreation.contains(beanName)){// 3. 从二级缓存获取早期引用beanearlySingletonObjects.get(beanName);if(beannull){// 4. 二级缓存无从三级缓存工厂创建早期引用ObjectFactoryfactorysingletonFactories.get(beanName);if(factory!null){beanfactory.getObject();// 三级缓存升级至二级缓存提升复用效率earlySingletonObjects.put(beanName,bean);singletonFactories.remove(beanName);}}returnbean;}// 5. 无循环依赖正常创建BeanreturncreateBean(beanName);}privateObjectcreateBean(StringbeanName){// 标记Bean正在创建singletonsInCreation.add(beanName);// 1. 实例化Bean构造方法ObjectbeaninstantiateBean(beanName);// 2. 存入三级缓存提前暴露工厂解决循环依赖AOP代理singletonFactories.put(beanName,()-{// 普通Bean返回原实例AOP场景返回代理对象returnbean;});// 3. 填充属性触发依赖注入、循环依赖检测populateBean(beanName,bean);// 4. 执行初始化方法PostConstruct、init-methodinitializeBean(beanName,bean);// 5. 完全初始化完毕升级至一级缓存清空临时缓存singletonObjects.put(beanName,bean);earlySingletonObjects.remove(beanName);singletonFactories.remove(beanName);singletonsInCreation.remove(beanName);returnbean;}// 模拟实例化、属性填充、初始化方法privateObjectinstantiateBean(StringbeanName){returnnull;}privatevoidpopulateBean(StringbeanName,Objectbean){}privatevoidinitializeBean(StringbeanName,Objectbean){}}4. 不同注入方式对循环依赖的支持4.1 字段注入Autowired✅ 支持循环依赖字段注入是Spring解决循环依赖的主流场景依托三级缓存提前暴露引用完美打破依赖闭环。ComponentpublicclassServiceA{AutowiredprivateServiceBserviceB;}ComponentpublicclassServiceB{AutowiredprivateServiceAserviceA;}4.2 Setter方法注入 ✅ 支持循环依赖Setter注入属于实例化后赋值Bean先完成构造实例化再填充属性可提前存入三级缓存支持循环依赖。ComponentpublicclassServiceA{privateServiceBserviceB;AutowiredpublicvoidsetServiceB(ServiceBserviceB){this.serviceBserviceB;}}ComponentpublicclassServiceB{privateServiceAserviceA;AutowiredpublicvoidsetServiceA(ServiceAserviceA){this.serviceAserviceA;}}4.3 构造器注入 ❌ 不支持循环依赖构造器注入是实例化阶段强制依赖Bean创建前必须先注入依赖对象无法提前暴露引用三级缓存机制无法生效直接抛出循环依赖异常。ComponentpublicclassServiceA{privateServiceBserviceB;// 构造器注入实例化时必须拥有完整ServiceB无法解决循环依赖publicServiceA(ServiceBserviceB){this.serviceBserviceB;}}ComponentpublicclassServiceB{privateServiceAserviceA;publicServiceB(ServiceAserviceA){this.serviceAserviceA;}}核心原因三级缓存的存入时机是构造方法执行完毕、实例化完成后构造器注入在实例化阶段就需要依赖对象无提前暴露机会。5. 特殊场景循环依赖处理5.1 Prototype原型作用域 ❌ 不支持循环依赖原型Bean每次获取都会新建实例Spring不会缓存原型Bean无三级缓存机制出现循环依赖直接抛出BeanCurrentlyInCreationException。Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)ComponentpublicclassPrototypeA{AutowiredprivatePrototypeBprototypeB;}Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)ComponentpublicclassPrototypeB{AutowiredprivatePrototypeAprototypeA;}5.2 Lazy注解解决构造器循环依赖 ✅通过Lazy延迟加载注入代理对象无需立即初始化目标Bean打破构造器循环依赖。ComponentpublicclassServiceA{privateServiceBserviceB;// 延迟加载注入代理对象使用时才初始化真实BeanpublicServiceA(LazyServiceBserviceB){this.serviceBserviceB;}}ComponentpublicclassServiceB{privateServiceAserviceA;publicServiceB(ServiceAserviceA){this.serviceAserviceA;}}5.3 DependsOn控制Bean加载顺序手动指定Bean加载优先级提前加载依赖Bean规避循环依赖但无法根治复杂闭环依赖。ComponentDependsOn(serviceB)// 优先加载serviceB再加载当前BeanpublicclassServiceA{AutowiredprivateServiceBserviceB;}ComponentpublicclassServiceB{AutowiredprivateServiceAserviceA;}6. AOP代理与循环依赖三级缓存存在的核心意义就是兼容AOP代理场景二级缓存无法动态生成代理对象会导致依赖注入的对象与最终Bean不一致。带AOP代理的循环依赖案例ServicepublicclassUserService{AutowiredprivateOrderServiceorderService;Transactional// 触发AOP动态代理publicvoidcreateUser(){// 业务逻辑}}ServicepublicclassOrderService{AutowiredprivateUserServiceuserService;// 注入的是UserService代理对象publicvoidcreateOrder(){userService.createUser();// 通过代理对象执行事务逻辑}}AOP代理处理核心流程实例化原始Bean对象无代理将可生成代理对象的ObjectFactory存入三级缓存其他Bean依赖当前Bean时三级缓存工厂动态生成代理对象保证全程注入、使用的都是代理Bean保持一致性避免事务失效、功能异常7. 高频面试题汇总Q1Spring核心如何解决单例Bean循环依赖A通过三级缓存机制提前暴露Bean早期引用解决一级缓存存放完全初始化完成的单例Bean二级缓存存放已实例化未初始化的早期Bean/代理引用三级缓存存放Bean工厂对象支持动态生成原始Bean或AOP代理Bean核心流程实例化Bean → 存入三级缓存提前暴露 → 填充属性解决依赖 → 初始化完成后升级至一级缓存。Q2哪些循环依赖Spring无法解决A构造器注入产生的循环依赖Prototype原型作用域Bean的循环依赖Async异步方法导致的自调用循环依赖多线程复杂嵌套循环依赖。Q3为什么需要三级缓存两级缓存不行A核心为了兼容AOP代理二级缓存只能存储固定对象无法动态生成代理三级缓存的ObjectFactory是函数式工厂可在被依赖时动态判断是否需要代理保证注入的Bean和最终容器中的Bean完全一致解决代理不一致问题。普通无代理Bean场景两级缓存可解决循环依赖。Q4三种注入方式循环依赖支持情况总结A字段注入、Setter注入支持实例化后赋值可提前暴露引用构造器注入不支持实例化阶段依赖前置无缓存暴露时机。Q5业务中如何优雅避免循环依赖A优先从设计层面解决其次使用技术手段规避接口解耦、事件驱动、延迟加载、上下文动态获取Bean。8. 循环依赖最佳解决方案与实践8.1 架构设计层面根治最优方案杜绝双向强依赖基于接口解耦、参数传值代替直接依赖。// 糟糕设计双向紧密耦合极易产生循环依赖ServicepublicclassBadUserService{AutowiredprivateBadOrderServiceorderService;}ServicepublicclassBadOrderService{AutowiredprivateBadUserServiceuserService;}// 优雅设计接口解耦单向依赖publicinterfaceUserService{voidcreateUser();}publicinterfaceOrderService{voidcreateOrder(LonguserId);}ServicepublicclassUserServiceImplimplementsUserService{privatefinalOrderServiceorderService;// 单向依赖接口无双向闭环publicUserServiceImpl(OrderServiceorderService){this.orderServiceorderService;}OverridepublicvoidcreateUser(){// 业务逻辑}}ServicepublicclassOrderServiceImplimplementsOrderService{// 通过参数获取用户信息不直接依赖UserServiceOverridepublicvoidcreateOrder(LonguserId){// 业务逻辑}}8.2 延迟获取BeanApplicationContext动态获取不直接注入Bean使用时从容器动态获取规避启动时循环依赖。ServicepublicclassSmartServiceA{privateApplicationContextapplicationContext;// 注入上下文不注入业务BeanpublicSmartServiceA(ApplicationContextapplicationContext){this.applicationContextapplicationContext;}publicvoiddoSomething(){// 业务调用时动态获取BeanServiceBserviceBapplicationContext.getBean(ServiceB.class);serviceB.process();}}8.3 事件驱动解耦推荐业务方案通过Spring事件机制代替直接方法调用彻底消除Bean双向依赖。ComponentpublicclassUserService{AutowiredprivateApplicationEventPublishereventPublisher;publicvoidcreateUser(Useruser){// 核心业务userRepository.save(user);// 发布事件解耦下游业务eventPublisher.publishEvent(newUserCreatedEvent(this,user.getId()));}}ComponentpublicclassOrderService{// 监听事件被动触发业务无直接依赖EventListenerpublicvoidhandleUserCreated(UserCreatedEventevent){createDefaultOrder(event.getUserId());}privatevoidcreateDefaultOrder(LonguserId){// 创建默认订单业务}}