如何解决SpringBoot2.6及之后版本取消了循环依赖的支持问题
作者:天空中那座城
1、问题
循环依赖指的是两个或者多个bean之间相互依赖,形成一个闭环。直接表现为两个service层互相调用对方。
此时会遇到以下问题:
2、报错
当启动项目时,可能出现程序不能启动的情况,查看调试日志,会提示:
The dependencies of some of the beans in the application context form a cycle...
如下图所示:
根据上述代码片段,应用程序存在以下循环依赖:
1. adminBorrowInfoController 依赖 borrowInfoServiceImpl
2. borrowInfoServiceImpl 依赖 lendServiceImpl
3. lendServiceImpl 依赖 lendItemServiceImpl
4. lendItemServiceImpl 又反过来依赖 lendServiceImpl
这样就形成了一个循环依赖的场景。
原因是SpringBoot 从 2.6.0 开始默认不允许出现 Bean 循环引用。而且这个是在Bean 定义上也就是类上就不允许出现循环引用。
3、解决方案
第1种、在全局配置文件设置允许循环引用存在
升级到Spring Boot 2.7及以上版本,可以通过spring.main.allow-circular-references=true配置属性明确开启循环依赖支持。
但我用的2.6.11也可以哦,2.6以上的可以试试。
spring: main: allow-circular-references:true
第2种、在SpringApplicationBuilder 添加设置允许循环引用
使用SpringApplicationBuilder来启动Spring Boot应用,并通过allowCircularReferences(true)方法开启了循环依赖支持。
public static void main(String[] args) { new SpringApplicationBuilder(DemoApplication.class).allowCircularReferences(true).run(args); }
第N种、还有很多种供大家了解使用
1. 构造器注入
- 在类中定义构造器,添加需要依赖的类作为参数
- 使用@Autowired注解构造器
- Spring会先实例化依赖类,然后通过构造器注入
2. @Lazy
- 在导致循环依赖的Bean上添加@Lazy注解
- Spring会延迟初始化这些Bean,先完成非Lazy的Bean初始化
- 然后再通过setter注入完成Lazy Bean的初始化
3. ObjectFactory
- 定义ObjectFactory属性,类型为对应类的ObjectFactory
- Spring会代理注入ObjectFactory,获取对象时才初始化目标Bean
4. 服务定位器
- 定义一个统一的服务定位器类
- Bean直接从定位器获取依赖对象,而不是注入依赖
5. 合并类
- 将互相依赖的类合并为一个类,避免相互依赖
6. 事件回调
- 使用事件或者回调方式实现解耦
- 一个类通过事件通知另一个类执行操作,而不是直接调用
7. 接口编程
- 类依赖接口,不依赖具体实现
- 具体实现通过setter注入接口
以上是一些主要的具体实现步骤,可以根据实际情况选择适合的方案。
总体上,出现循环依赖通常意味着系统设计需要优化和解耦,需要重新梳理服务的职责和依赖关系,减少不必要的互相依赖,以提高内聚性和可维护性。
这些仅为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。