spring bean循环依赖是什么?项目中什么时候会碰到这种情况?解决方案是?

Spring Bean 循环依赖详解


什么是循环依赖?


循环依赖是指两个或多个 Bean 相互依赖,形成一个依赖环:


```

Bean A → 依赖 → Bean B

 ↑                    ↓

  ←  依赖   ←

```


代码示例


```java

// 情况1:构造函数循环依赖(Spring无法解决)

@Service

public class ServiceA {

   private final ServiceB serviceB;

   

   @Autowired

   public ServiceA(ServiceB serviceB) {  // 构造器注入

       this.serviceB = serviceB;

   }

}


@Service

public class ServiceB {

   private final ServiceA serviceA;

   

   @Autowired

   public ServiceB(ServiceA serviceA) {  // 构造器注入

       this.serviceA = serviceA;

   }

}

```


```java

// 情况2:属性/Setter注入循环依赖(Spring可以解决)

@Service

public class UserService {

   @Autowired

   private RoleService roleService;  // 属性注入

   

   public void createUser() {

       roleService.assignRole();

   }

}


@Service

public class RoleService {

   @Autowired

   private UserService userService;  // 属性注入

   

   public void assignRole() {

       userService.createUser();

   }

}

```


什么时候会遇到循环依赖?


1. 架构设计问题


```java

// 反例:紧密耦合的业务层

@Service

public class OrderService {

   @Autowired

   private PaymentService paymentService;

   

   public void createOrder() {

       // 订单需要支付

       paymentService.processPayment();

   }

}


@Service

public class PaymentService {

   @Autowired

   private OrderService orderService;

   

   public void processPayment() {

       // 支付需要订单信息

       orderService.updateOrderStatus();  // 设计问题!

   }

}

```


2. 缓存与业务逻辑耦合


```java

@Service

public class ProductService {

   @Autowired

   private CacheService cacheService;

   

   public Product getProduct(Long id) {

       return cacheService.getProduct(id);

   }

}


@Service

public class CacheService {

   @Autowired

   private ProductService productService;  // 需要从数据库加载

   

   public Product getProduct(Long id) {

       // 缓存未命中时调用 ProductService

       return productService.loadFromDB(id);

   }

}

```


3. 事件监听器相互调用


```java

@Component

public class OrderEventListener {

   @Autowired

   private EmailService emailService;

   

   @EventListener

   public void handleOrderEvent(OrderEvent event) {

       emailService.sendNotification(event);

   }

}


@Component

public class EmailService {

   @Autowired

   private OrderEventListener orderEventListener;  // 错误的设计

   

   public void sendNotification(OrderEvent event) {

       // 发送邮件后触发其他事件

       orderEventListener.onEmailSent(event);

   }

}

```


4. 配置类相互依赖


```java

@Configuration

public class ConfigA {

   @Autowired

   private ConfigB configB;

   

   @Bean

   public ServiceA serviceA() {

       return new ServiceA(configB.serviceB());

   }

}


@Configuration

public class ConfigB {

   @Autowired

   private ConfigA configA;

   

   @Bean

   public ServiceB serviceB() {

       return new ServiceB(configA.serviceA());

   }

}

```


5. 常见的实际场景


```java

// 场景1:权限验证

@Service

public class SecurityService {

   @Autowired

   private UserService userService;  // 需要验证用户

   

   public boolean hasPermission(User user, String permission) {

       return userService.checkPermission(user, permission);

   }

}


@Service

public class UserService {

   @Autowired

   private SecurityService securityService;  // 需要安全验证

   

   @PreAuthorize("hasRole('ADMIN')")

   public User updateUser(User user) {

       // 更新用户

   }

}


// 场景2:消息处理链

@Service  

public class MessageHandlerA {

   @Autowired

   private MessageHandlerB nextHandler;

   

   public void handle(Message msg) {

       // 处理消息

       nextHandler.handle(msg);

   }

}


@Service

public class MessageHandlerB {

   @Autowired

   private MessageHandlerA previousHandler;  // 需要回溯

   

   public void handle(Message msg) {

       if (msg.needsRetry()) {

           previousHandler.handle(msg);

       }

   }

}

```


Spring 如何解决循环依赖?


三级缓存机制


```java

// Spring 内部的三级缓存

public class DefaultSingletonBeanRegistry {

   

   // 第一级缓存:完整的单例 Bean

   private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

   

   // 第二级缓存:提前暴露的早期引用(半成品)

   private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

   

   // 第三级缓存:对象工厂,用于创建代理对象

   private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

}

```


解决流程(属性注入)


```

创建 A → 实例化 A → 放入三级缓存 → 填充属性(需要 B)

创建 B → 实例化 B → 放入三级缓存 → 填充属性(需要 A)

   ↓

从三级缓存获取 A 的早期引用 → 注入给 B → 完成 B

   ↓

B 返回给 A → A 完成初始化 → 移入一级缓存

```


解决方案


方案1:重新设计(首选)


```java

// 坏的设计:循环依赖

@Service

public class OrderService {

   @Autowired

   private PaymentService paymentService;

}


@Service  

public class PaymentService {

   @Autowired

   private OrderService orderService;

}


// 好的设计:提取公共逻辑

@Service

public class OrderService {

   private final OrderProcessor orderProcessor;

   

   public OrderService(OrderProcessor processor) {

       this.orderProcessor = processor;

   }

}


@Service  

public class PaymentService {

   private final OrderProcessor orderProcessor;

   

   public PaymentService(OrderProcessor processor) {

       this.orderProcessor = processor;

   }

}


@Component

public class OrderProcessor {

   // 公共业务逻辑

   public void processOrder(Order order) {

       // 处理订单

   }

}

```


方案2:使用 Setter/方法注入


```java

@Service

public class ServiceA {

   private ServiceB serviceB;

   

   @Autowired

   public void setServiceB(ServiceB serviceB) {  // Setter注入

       this.serviceB = serviceB;

   }

}


@Service

public class ServiceB {

   private ServiceA serviceA;

   

   @Autowired  

   public void setServiceA(ServiceA serviceA) {  // Setter注入

       this.serviceA = serviceA;

   }

}

```


方案3:使用 @Lazy


```java

@Service

public class ServiceA {

   private final ServiceB serviceB;

   

   @Autowired

   public ServiceA(@Lazy ServiceB serviceB) {  // 延迟加载

       this.serviceB = serviceB;

   }

}


@Service

public class ServiceB {

   private final ServiceA serviceA;

   

   @Autowired

   public ServiceB(ServiceA serviceA) {

       this.serviceA = serviceA;

   }

}

```


方案4:使用 ApplicationContext


```java

@Service

public class ServiceA implements ApplicationContextAware {

   private ApplicationContext context;

   private ServiceB serviceB;

   

   @Override

   public void setApplicationContext(ApplicationContext context) {

       this.context = context;

   }

   

   @PostConstruct

   public void init() {

       this.serviceB = context.getBean(ServiceB.class);  // 手动获取

   }

}


@Service

public class ServiceB {

   @Autowired

   private ServiceA serviceA;  // 正常注入

}

```


方案5:使用 ObjectProvider(Spring 4.3+)


```java

@Service

public class ServiceA {

   private final ObjectProvider<ServiceB> serviceBProvider;

   

   @Autowired

   public ServiceA(ObjectProvider<ServiceB> serviceBProvider) {

       this.serviceBProvider = serviceBProvider;

   }

   

   public void doSomething() {

       ServiceB serviceB = serviceBProvider.getIfAvailable();  // 按需获取

       if (serviceB != null) {

           serviceB.process();

       }

   }

}


@Service

public class ServiceB {

   @Autowired

   private ServiceA serviceA;

}

```


方案6:接口分离


```java

// 定义接口

public interface IOrderService {

   void createOrder();

}


public interface IPaymentService {

   void processPayment();

}


// 实现类1

@Service

public class OrderService implements IOrderService {

   private final IPaymentService paymentService;

   

   @Autowired

   public OrderService(IPaymentService paymentService) {

       this.paymentService = paymentService;

   }

}


// 实现类2  

@Service

public class PaymentService implements IPaymentService {

   private final IOrderService orderService;

   

   @Autowired

   public PaymentService(IOrderService orderService) {

       this.orderService = orderService;

   }

}


// 配置类解决循环依赖

@Configuration

public class ServiceConfig {

   

   @Bean

   @DependsOn("paymentService")  // 明确依赖顺序

   public IOrderService orderService(IPaymentService paymentService) {

       return new OrderService(paymentService);

   }

   

   @Bean

   public IPaymentService paymentService() {

       return new PaymentService(null);  // 先创建,后设置

   }

   

   @Bean

   public Object postProcess(IPaymentService paymentService,

                             IOrderService orderService) {

       // 通过后处理器设置依赖

       ((PaymentService) paymentService).setOrderService(orderService);

       return null;

   }

}

```


Spring Boot 2.6+ 的变化


从 Spring Boot 2.6 开始,默认禁止了循环依赖:


```yaml

# application.yml

spring:

 main:

   allow-circular-references: false  # 默认false,禁止循环依赖

```


```java

// 如果需要允许循环依赖(不推荐)

@SpringBootApplication

public class Application {

   public static void main(String[] args) {

       new SpringApplicationBuilder(Application.class)

           .allowCircularReferences(true)  // 允许循环依赖

           .run(args);

   }

}

```


最佳实践和检测工具


1. 使用架构检测工具


```xml

<!-- ArchUnit 依赖 -->

<dependency>

   <groupId>com.tngtech.archunit</groupId>

   <artifactId>archunit-junit5</artifactId>

   <version>1.0.0</version>

   <scope>test</scope>

</dependency>

```


```java

// 测试代码,检测循环依赖

@AnalyzeClasses(packages = "com.example")

public class ArchitectureTest {

   

   @Test

   public void shouldHaveNoCyclicDependencies() {

       slices()

           .matching("com.example.(*)..")

           .should().beFreeOfCycles();  // 检测循环依赖

   }

   

   @Test

   public void serviceLayerShouldNotHaveCycles() {

       SliceAssignment assignment = new SliceAssignment() {

           @Override

           public String getDescription() {

               return "按服务划分";

           }

           

           @Override

           public String apply(JavaClass javaClass) {

               if (javaClass.getPackageName().contains(".service.")) {

                   return javaClass.getPackageName();

               }

               return null;

           }

       };

       

       ArchRule rule = slices().assignedFrom(assignment)

           .should().beFreeOfCycles();

       

       rule.check(importedClasses);

   }

}

```


2. IDE 插件检测


· IntelliJ IDEA: 内置循环依赖检测

· Eclipse: 安装相关架构插件

· SonarQube: 代码质量检测


3. 代码审查清单


```java

// 审查点1:构造函数注入

@Service

public class BadExample {

   @Autowired

   private AnotherService service;  // 属性注入,可能隐藏循环依赖

   

   public BadExample() {

       // 空构造器

   }

}


@Service  

public class GoodExample {

   private final AnotherService service;

   

   public GoodExample(AnotherService service) {  // 构造器注入

       this.service = service;  // 立即发现循环依赖

   }

}


// 审查点2:依赖方向

// 从高层到底层:Controller → Service → Repository

// 不要出现反向依赖

```


常见问题排查


错误信息示例


```

Error creating bean with name 'serviceA':

Requested bean is currently in creation: Is there an unresolvable circular reference?

```


排查步骤


```java

// 1. 查看 Bean 创建日志

@Component

public class BeanCreationLogger implements BeanPostProcessor {

   

   @Override

   public Object postProcessBeforeInitialization(Object bean, String beanName) {

       System.out.println("Creating bean: " + beanName);

       return bean;

   }

}


// 2. 使用 Spring Boot Actuator

// application.yml

management:

 endpoints:

   web:

     exposure:

       include: beans

// 访问:http://localhost:8080/actuator/beans


// 3. 使用调试模式

@Component

public class CircularDependencyDetector implements SmartInitializingSingleton {

   

   @Autowired

   private ConfigurableListableBeanFactory beanFactory;

   

   @Override

   public void afterSingletonsInstantiated() {

       String[] beanNames = beanFactory.getBeanDefinitionNames();

       for (String beanName : beanNames) {

           BeanDefinition bd = beanFactory.getBeanDefinition(beanName);

           if (bd.isSingleton()) {

               try {

                   Object bean = beanFactory.getBean(beanName);

                   System.out.println("成功创建: " + beanName);

               } catch (BeanCurrentlyInCreationException e) {

                   System.err.println("循环依赖检测到: " + beanName);

                   System.err.println(e.getMessage());

               }

           }

       }

   }

}

```


总结


解决方案 适用场景 优点 缺点

重新设计 所有场景 根本解决,代码清晰 需要重构

Setter注入 简单循环 Spring支持,简单 破坏不变性

@Lazy 构造函数注入 延迟加载,避免初始化死锁 可能隐藏设计问题

ApplicationContext 复杂场景 灵活控制 增加耦合

ObjectProvider Spring 4.3+ 推荐方式,类型安全 需要手动获取

接口分离 架构优化 符合设计原则 增加接口数量


黄金法则:


1. 优先使用构造器注入,它能尽早暴露循环依赖

2. 循环依赖通常是设计问题的信号,应该首先考虑重构

3. 如果必须存在循环依赖,使用 @Lazy 或 Setter注入

4. 在 Spring Boot 2.6+ 中,默认禁止循环依赖,这是为了鼓励更好的设计