【Spring Boot】Spring Boot解决循环依赖

循环依赖的定义

循环依赖指的是两个或多个Bean相互依赖,形成闭环。例如,BeanA依赖BeanB,BeanB又依赖BeanA,导致Spring容器无法正确初始化这些Bean。

构造器循环依赖

构造器注入的循环依赖无法解决,因为Spring在创建Bean时必须先完成构造器调用。这种情况会直接抛出BeanCurrentlyInCreationException。

解决方案:

  • 改为使用Setter注入或字段注入
  • 重新设计代码结构,消除循环依赖

Setter/字段注入循环依赖

对于Setter注入或字段注入的循环依赖,Spring通过三级缓存机制可以解决:

  1. 一级缓存(单例池):存放完全初始化好的Bean
  2. 二级缓存:存放早期的Bean引用(已实例化但未完全初始化)
  3. 三级缓存:存放Bean工厂,用于生成早期引用

Spring处理流程:

  • 创建BeanA时,先将其工厂放入三级缓存
  • 发现需要BeanB,开始创建BeanB
  • 创建BeanB时发现需要BeanA,从三级缓存获取BeanA的早期引用
  • BeanB创建完成后,BeanA可以完成初始化

最佳实践解决方案

使用@Lazy注解 在其中一个依赖上添加@Lazy,延迟加载打破循环:

java 复制代码
@Service
public class ServiceA {
    private final ServiceB serviceB;
    
    @Autowired
    public ServiceA(@Lazy ServiceB serviceB) {
        this.serviceB = serviceB;
    }
}

重新设计代码结构

  • 提取公共逻辑到第三个服务中
  • 使用接口分离依赖
  • 考虑使用事件驱动模式代替直接调用

使用ApplicationContextAware

java 复制代码
@Service
public class ServiceA implements ApplicationContextAware {
    private ApplicationContext context;
    
    @Override
    public void setApplicationContext(ApplicationContext ctx) {
        this.context = ctx;
    }
    
    public void someMethod() {
        ServiceB serviceB = context.getBean(ServiceB.class);
        // 使用serviceB
    }
}

配置文件中允许循环依赖 Spring Boot 2.6+默认禁止循环依赖,如需允许:

properties 复制代码
spring.main.allow-circular-references=true

注意事项

  • 循环依赖通常是设计问题,应优先考虑重构
  • 在测试环境下允许循环依赖可能掩盖设计缺陷
  • 过多使用@Lazy可能导致运行时错误更难排查
  • Spring的解决方案仅适用于单例作用域的Bean

代码结构优化示例

将共享功能提取到新服务:

java 复制代码
@Service
public class CommonService {
    // 共享逻辑
}

@Service
public class ServiceA {
    private final CommonService commonService;
}

@Service
public class ServiceB {
    private final CommonService commonService;
}
相关推荐
今年下半年4 分钟前
【消息队列】Spring Boot 集成 Kafka 消息队列:确保消费完成(手动提交偏移量+幂等判断+失败重试机制)
spring boot·kafka·幂等·失败重试
计算机毕设定制辅导-无忧学长5 分钟前
《校园食堂在线订餐小程序的设计与实现》
java·vue.js·spring boot·微信小程序·uniapp·校园食堂在线订餐小程序
夜之眷属10 分钟前
服务启动即崩:InetAddress.getLocalHost() 抛 UnknownHostException 排查记
java·运维·后端·docker
IT研究室13 分钟前
最新计算机毕业设计选题推荐-基于spring boot的食品安全信息管理系统-网站-文档指导-Java-springboot
java·spring boot·课程设计
Sayai36 分钟前
MCP Server 开发实战:Spring AI 把后端日志查询暴露给 AI Agent(7 条设计原则与踩坑实录)
java·人工智能·ai agent·spring ai·mcp
大牧师42 分钟前
Mybatis 框架教程
java·数据库·mybatis·数据持久化·orm
SunnyDays101143 分钟前
Java 合并 PDF 文件:完整合并、指定页面合并与流合并
java·开发语言·合并pdf
源码宝1 小时前
云HIS系统源码,HIS全套源码,支持监管系统对接与二次开发
java·源码·电子病历·云his系统·程序代码·全套源码
萧瑟余晖1 小时前
Spring MVC拦截器异常处理与跨域详解
java·spring·mvc