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

循环依赖的定义

循环依赖是指两个或多个Bean相互依赖,形成闭环。例如Bean A依赖Bean B,Bean B又依赖Bean A。Spring Boot默认支持单例作用域的循环依赖,但原型作用域不支持。

使用构造器注入的解决方案

构造器注入是解决循环依赖的首选方式。通过在构造器中明确依赖关系,可以避免循环依赖问题。这种方式在启动时就会抛出异常,便于早期发现问题。

java 复制代码
@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;
    }
}

使用Setter注入的解决方案

Setter注入通过方法注入依赖,Spring会先创建Bean实例,再通过Setter方法注入依赖。这种方式允许循环依赖的存在,但可能导致运行时问题。

java 复制代码
@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注解延迟加载

@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;
    }
}

重新设计代码结构

从根本上解决循环依赖的方法是重新设计组件关系。常见的重构方式包括:

  • 提取公共逻辑到第三方服务
  • 使用事件驱动架构
  • 引入接口隔离

使用ApplicationContext获取Bean

在极端情况下,可以通过ApplicationContext手动获取Bean,但不推荐作为常规解决方案。

java 复制代码
@Service
public class ServiceA {
    @Autowired
    private ApplicationContext context;

    public ServiceB getServiceB() {
        return context.getBean(ServiceB.class);
    }
}

@Service
public class ServiceB {
    @Autowired
    private ApplicationContext context;

    public ServiceA getServiceA() {
        return context.getBean(ServiceA.class);
    }
}

配置允许循环依赖

Spring Boot 2.6+默认禁用了循环依赖,如需允许可以在配置中设置:

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

但这种方法只是临时解决方案,长期应优化代码结构。

相关推荐
苏打水com几秒前
第十七篇:Day49-51 前端工程化进阶——从“手动”到“自动化”(对标职场“提效降本”需求)
前端·javascript·css·vue.js·html
文心快码BaiduComate1 分钟前
Comate强力赋能:「趣绘像素岛」从体验泥潭到高性能可用的蜕变之路
前端·后端·程序员
『 时光荏苒 』3 分钟前
使用Vue播放M3U8视频流的方法
前端·javascript·vue.js
阿杆.8 分钟前
如何在 Spring Boot 中接入 Amazon ElastiCache
java·spring boot·后端
Apifox9 分钟前
Apifox + AI:接口自动化测试的智能化实践
前端·后端·测试
Tjohn99 分钟前
前后端分离项目(Vue-SpringBoot)迁移记录
前端·vue.js·spring boot
别惹CC11 分钟前
Spring AI 进阶之路04:集成 SearXNG 实现联网搜索
java·后端·spring
invicinble11 分钟前
springboot的日志体系
java·spring boot·后端
CaoLv15 分钟前
无需后端!用 React + WebLLM 把大模型装进浏览器,手撸一个“有脾气”的 AI 机器人 🤖
前端
消防大队VUE支队17 分钟前
🗓️ 2262年将有两个春节!作为前端的你,日历控件真的写对了吗?
前端·javascript