Spring循环依赖解决方案引言循环依赖是Spring应用中常见的问题当两个或多个Bean相互依赖形成闭环时Spring容器无法正常创建这些Bean。Spring框架通过三级缓存机制解决了大部分单例Bean的循环依赖问题但某些场景下循环依赖仍然会导致启动失败。本文将深入分析Spring循环依赖的原理、三级缓存机制以及各种解决方案。一、循环依赖类型1.1 构造器循环依赖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; } } // ServiceA - ServiceB - ServiceA 循环依赖 // 构造器注入会导致启动失败1.2 Setter循环依赖Service public class ServiceA { private ServiceB serviceB; Autowired public void setServiceB(ServiceB serviceB) { this.serviceB serviceB; } } Service public class ServiceB { private ServiceA serviceA; Autowired public void setServiceA(ServiceA serviceA) { this.serviceA serviceA; } } // Setter注入可以通过三级缓存解决1.3 Prototype循环依赖Bean Scope(prototype) public ServiceA serviceA(ServiceB serviceB) { return new ServiceA(serviceB); } Bean Scope(prototype) public ServiceB serviceB(ServiceA serviceA) { return new ServiceB(serviceA); } // Prototype作用域Bean不支持循环依赖解决二、三级缓存机制2.1 缓存结构public class DefaultSingletonBeanRegistry { // 一级缓存已完成的单例Bean private final MapString, Object singletonObjects new ConcurrentHashMap(); // 二级缓存提前暴露的Bean未完成属性填充 private final MapString, Object earlySingletonObjects new ConcurrentHashMap(); // 三级缓存Bean创建工厂 private final MapString, ObjectFactory? singletonFactories new ConcurrentHashMap(); }2.2 获取Bean流程protected Object getSingleton(String beanName, boolean allowEarlyCreation) { // 1. 从一级缓存获取 Object singleton singletonObjects.get(beanName); // 2. 如果不存在且正在创建 if (singleton null isSingletonCurrentlyInCreation(beanName)) { synchronized (singletonObjects) { // 3. 从二级缓存获取 singleton earlySingletonObjects.get(beanName); if (singleton null) { // 4. 从三级缓存获取 ObjectFactory? factory singletonFactories.get(beanName); if (factory ! null) { singleton factory.getObject(); // 移动到二级缓存 earlySingletonObjects.put(beanName, singleton); singletonFactories.remove(beanName); } } } } return singleton; }三、循环依赖解决过程3.1 A依赖BB依赖A// 创建Bean A的流程 1. 调用 getSingleton(a) 2. 调用 createBean(a) 3. 添加到正在创建集合 4. 创建A实例添加到三级缓存 5. 属性填充发现依赖B 6. 调用 getSingleton(b) 7. 调用 createBean(b) 8. 创建B实例添加到三级缓存 9. 属性填充发现依赖A 10. 调用 getSingleton(a) 11. 从三级缓存获取A的ObjectFactory 12. 获取早期A移到二级缓存 13. 完成B的属性填充和初始化 14. B添加到一级缓存 15. 完成A的属性填充和初始化 16. A添加到一级缓存3.2 时序图A创建 - 三级缓存添加A工厂 - 填充B - B创建 - 三级缓存添加B工厂 - 填充A - 获取A工厂 - 创建早期A - 填充早期A给B - 完成B - 完成A四、构造器循环依赖4.1 无法解决的原因// 构造器注入必须在创建实例时完成 public ServiceA(ServiceB serviceB) { this.serviceB serviceB; // 这里需要B已创建 } public ServiceB(ServiceA serviceA) { this.serviceA serviceA; // 这里需要A已创建 } // 无法打破循环因为实例化就需要完整依赖4.2 解决方案Setter注入Service public class ServiceA { private ServiceB serviceB; Autowired public void setServiceB(ServiceB serviceB) { this.serviceB serviceB; } } Service public class ServiceB { private ServiceA serviceA; Autowired public void setServiceA(ServiceA serviceA) { this.serviceA serviceA; } }五、Lazy注解解决5.1 基本用法Service public class ServiceA { private final ServiceB serviceB; public ServiceA(Lazy ServiceB serviceB) { this.serviceB serviceB; } } Service public class ServiceB { private final ServiceA serviceA; public ServiceB(Lazy ServiceA serviceA) { this.serviceA serviceA; } }5.2 原理Lazy创建代理对象注入实际Bean在首次使用时才创建避免了初始化时的循环。// Lazy生成的是代理对象 public class ServiceA { private ServiceB serviceB; public ServiceA(LazyObjectFactoryServiceB lazyFactory) { this.serviceB lazyFactory.getObject(); } }六、DependsOn注解6.1 强制初始化顺序Service DependsOn(serviceA) public class ServiceB { private ServiceA serviceA; public ServiceB(ServiceA serviceA) { this.serviceA serviceA; } } Service public class ServiceA { // A会先于B创建 }6.2 使用场景Configuration DependsOn({dataSourceInitializer, cacheInitializer}) public class DatabaseConfig { // 确保初始化器先执行 }七、ObjectProvider延迟注入7.1 基本用法Service public class ServiceA { private final ObjectProviderServiceB serviceBProvider; public ServiceA(ObjectProviderServiceB serviceBProvider) { this.serviceBProvider serviceBProvider; } public void doSomething() { ServiceB serviceB serviceBProvider.getIfAvailable(); // 必要时获取 } }7.2 ObjectFactoryService public class ServiceB { private final ObjectFactoryServiceA serviceAFactory; public ServiceB(ObjectFactoryServiceA serviceAFactory) { this.serviceAFactory serviceAFactory; } public void doSomething() { ServiceA serviceA serviceAFactory.getObject(); } }八、重构解决循环8.1 提取公共依赖// Before: A - B - C - A 循环 // After: 提取C到新服务 Service public class CommonService { // 提取公共逻辑 } Service public class ServiceA { private CommonService commonService; } Service public class ServiceB { private CommonService commonService; }8.2 事件驱动解耦Service public class ServiceA { private final ApplicationEventPublisher publisher; public ServiceA(ApplicationEventPublisher publisher) { this.publisher publisher; } public void doSomething() { publisher.publishEvent(new OrderCreatedEvent(this)); } } Service public class ServiceB { EventListener public void handleOrderCreated(OrderCreatedEvent event) { // 异步处理不直接依赖 } }九、自定义Scope解决9.1 ThreadLocal ScopeComponent public class ThreadScope implements Scope { private final ThreadLocalMapString, Object threadScope ThreadLocal.withInitial(HashMap::new); Override public Object get(String name, ObjectFactory? objectFactory) { MapString, Object scope threadScope.get(); Object object scope.get(name); if (object null) { object objectFactory.getObject(); scope.put(name, object); } return object; } Override public Object remove(String name) { return threadScope.get().remove(name); } }十、Spring循环依赖配置10.1 允许早期代理spring: main: allow-circular-references: true # Spring Boot 2.6默认禁止10.2 代理模式Configuration public class ProxyConfig { Bean Scope(proxyMode ScopedProxyMode.TARGET_CLASS) public ServiceA serviceA() { return new ServiceA(); } }总结Spring的三级缓存机制解决了大部分单例Bean的Setter循环依赖问题但构造器循环依赖无法解决。通过Lazy注解、ObjectProvider、事件驱动等手段可以有效打破循环依赖。最根本的解决方案是通过合理的架构设计避免循环依赖的产生。
Spring循环依赖解决方案
发布时间:2026/5/18 16:58:50
Spring循环依赖解决方案引言循环依赖是Spring应用中常见的问题当两个或多个Bean相互依赖形成闭环时Spring容器无法正常创建这些Bean。Spring框架通过三级缓存机制解决了大部分单例Bean的循环依赖问题但某些场景下循环依赖仍然会导致启动失败。本文将深入分析Spring循环依赖的原理、三级缓存机制以及各种解决方案。一、循环依赖类型1.1 构造器循环依赖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; } } // ServiceA - ServiceB - ServiceA 循环依赖 // 构造器注入会导致启动失败1.2 Setter循环依赖Service public class ServiceA { private ServiceB serviceB; Autowired public void setServiceB(ServiceB serviceB) { this.serviceB serviceB; } } Service public class ServiceB { private ServiceA serviceA; Autowired public void setServiceA(ServiceA serviceA) { this.serviceA serviceA; } } // Setter注入可以通过三级缓存解决1.3 Prototype循环依赖Bean Scope(prototype) public ServiceA serviceA(ServiceB serviceB) { return new ServiceA(serviceB); } Bean Scope(prototype) public ServiceB serviceB(ServiceA serviceA) { return new ServiceB(serviceA); } // Prototype作用域Bean不支持循环依赖解决二、三级缓存机制2.1 缓存结构public class DefaultSingletonBeanRegistry { // 一级缓存已完成的单例Bean private final MapString, Object singletonObjects new ConcurrentHashMap(); // 二级缓存提前暴露的Bean未完成属性填充 private final MapString, Object earlySingletonObjects new ConcurrentHashMap(); // 三级缓存Bean创建工厂 private final MapString, ObjectFactory? singletonFactories new ConcurrentHashMap(); }2.2 获取Bean流程protected Object getSingleton(String beanName, boolean allowEarlyCreation) { // 1. 从一级缓存获取 Object singleton singletonObjects.get(beanName); // 2. 如果不存在且正在创建 if (singleton null isSingletonCurrentlyInCreation(beanName)) { synchronized (singletonObjects) { // 3. 从二级缓存获取 singleton earlySingletonObjects.get(beanName); if (singleton null) { // 4. 从三级缓存获取 ObjectFactory? factory singletonFactories.get(beanName); if (factory ! null) { singleton factory.getObject(); // 移动到二级缓存 earlySingletonObjects.put(beanName, singleton); singletonFactories.remove(beanName); } } } } return singleton; }三、循环依赖解决过程3.1 A依赖BB依赖A// 创建Bean A的流程 1. 调用 getSingleton(a) 2. 调用 createBean(a) 3. 添加到正在创建集合 4. 创建A实例添加到三级缓存 5. 属性填充发现依赖B 6. 调用 getSingleton(b) 7. 调用 createBean(b) 8. 创建B实例添加到三级缓存 9. 属性填充发现依赖A 10. 调用 getSingleton(a) 11. 从三级缓存获取A的ObjectFactory 12. 获取早期A移到二级缓存 13. 完成B的属性填充和初始化 14. B添加到一级缓存 15. 完成A的属性填充和初始化 16. A添加到一级缓存3.2 时序图A创建 - 三级缓存添加A工厂 - 填充B - B创建 - 三级缓存添加B工厂 - 填充A - 获取A工厂 - 创建早期A - 填充早期A给B - 完成B - 完成A四、构造器循环依赖4.1 无法解决的原因// 构造器注入必须在创建实例时完成 public ServiceA(ServiceB serviceB) { this.serviceB serviceB; // 这里需要B已创建 } public ServiceB(ServiceA serviceA) { this.serviceA serviceA; // 这里需要A已创建 } // 无法打破循环因为实例化就需要完整依赖4.2 解决方案Setter注入Service public class ServiceA { private ServiceB serviceB; Autowired public void setServiceB(ServiceB serviceB) { this.serviceB serviceB; } } Service public class ServiceB { private ServiceA serviceA; Autowired public void setServiceA(ServiceA serviceA) { this.serviceA serviceA; } }五、Lazy注解解决5.1 基本用法Service public class ServiceA { private final ServiceB serviceB; public ServiceA(Lazy ServiceB serviceB) { this.serviceB serviceB; } } Service public class ServiceB { private final ServiceA serviceA; public ServiceB(Lazy ServiceA serviceA) { this.serviceA serviceA; } }5.2 原理Lazy创建代理对象注入实际Bean在首次使用时才创建避免了初始化时的循环。// Lazy生成的是代理对象 public class ServiceA { private ServiceB serviceB; public ServiceA(LazyObjectFactoryServiceB lazyFactory) { this.serviceB lazyFactory.getObject(); } }六、DependsOn注解6.1 强制初始化顺序Service DependsOn(serviceA) public class ServiceB { private ServiceA serviceA; public ServiceB(ServiceA serviceA) { this.serviceA serviceA; } } Service public class ServiceA { // A会先于B创建 }6.2 使用场景Configuration DependsOn({dataSourceInitializer, cacheInitializer}) public class DatabaseConfig { // 确保初始化器先执行 }七、ObjectProvider延迟注入7.1 基本用法Service public class ServiceA { private final ObjectProviderServiceB serviceBProvider; public ServiceA(ObjectProviderServiceB serviceBProvider) { this.serviceBProvider serviceBProvider; } public void doSomething() { ServiceB serviceB serviceBProvider.getIfAvailable(); // 必要时获取 } }7.2 ObjectFactoryService public class ServiceB { private final ObjectFactoryServiceA serviceAFactory; public ServiceB(ObjectFactoryServiceA serviceAFactory) { this.serviceAFactory serviceAFactory; } public void doSomething() { ServiceA serviceA serviceAFactory.getObject(); } }八、重构解决循环8.1 提取公共依赖// Before: A - B - C - A 循环 // After: 提取C到新服务 Service public class CommonService { // 提取公共逻辑 } Service public class ServiceA { private CommonService commonService; } Service public class ServiceB { private CommonService commonService; }8.2 事件驱动解耦Service public class ServiceA { private final ApplicationEventPublisher publisher; public ServiceA(ApplicationEventPublisher publisher) { this.publisher publisher; } public void doSomething() { publisher.publishEvent(new OrderCreatedEvent(this)); } } Service public class ServiceB { EventListener public void handleOrderCreated(OrderCreatedEvent event) { // 异步处理不直接依赖 } }九、自定义Scope解决9.1 ThreadLocal ScopeComponent public class ThreadScope implements Scope { private final ThreadLocalMapString, Object threadScope ThreadLocal.withInitial(HashMap::new); Override public Object get(String name, ObjectFactory? objectFactory) { MapString, Object scope threadScope.get(); Object object scope.get(name); if (object null) { object objectFactory.getObject(); scope.put(name, object); } return object; } Override public Object remove(String name) { return threadScope.get().remove(name); } }十、Spring循环依赖配置10.1 允许早期代理spring: main: allow-circular-references: true # Spring Boot 2.6默认禁止10.2 代理模式Configuration public class ProxyConfig { Bean Scope(proxyMode ScopedProxyMode.TARGET_CLASS) public ServiceA serviceA() { return new ServiceA(); } }总结Spring的三级缓存机制解决了大部分单例Bean的Setter循环依赖问题但构造器循环依赖无法解决。通过Lazy注解、ObjectProvider、事件驱动等手段可以有效打破循环依赖。最根本的解决方案是通过合理的架构设计避免循环依赖的产生。