使用了SpringBoot2.6及以上版本的,如果要允许循环依赖,可以作如下设置 :
方案二:允许循环引用
此方案更像是绕过问题而非解决问题本身!!!
它是一种妥协方案而非最佳实践。在Spring Boot 2.6.0之前版本无需担心此问题(默认允许循环引用),若你准备使用2.6.x但现实情况依旧必须允许循环引用那该怎么办呢?
有哪些现实情况呢?诸如:老项目升级Spring Boot版本需要保持向下兼容性;公司coder的水平不一,强制高标准的要求将会严重影响到生产效率等等
为此,做法只有一个:禁用默认行为(允许循环引用)。具体做法也很简单,其实在文上启动失败的报错详情里Spring Boot已非常贴心的告诉你了:所以只需在配置文件application.properties
里加上这个属性:
spring.main.allow-circular-references = true
再次启用Spring Boot 2.6.0版本的应用:正常启动。
除了加属性这个方法之外,也可以通过启动类API的方式来设置,能达到同样效果:
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class)
.allowCircularReferences(true) // 允许循环引用
.run(args);
}
我们知道,允许循环引用与否其实是Spring Framework
的能力,Spring Boot只是将其暴露为属性参数方便开发者来控制而已。那么问题来了,如果是一个构建在纯Spring Framework
上的应用,如何禁止循环引用呢?你知道怎么做吗?欢迎在留言区讨论作答,或私聊我探讨学习~
加餐:允许循环引用了但依旧报错
也许你一直认为Spring已经解决循环引用问题了,所以在使用过程中可以“毫无顾忌”。非也,某些“特殊”场景下可能依旧会碰壁,并且问题还很隐蔽不好定位,不信你看我层层递进的给你描述这个场景:
说明:以下代码在允许循环引用的Spring Boot场景下演示运行
基础代码:
本例使用
@PostConstruct
来模拟触发方法调用,效果和Controller里调Service方法一样哈
@Service
public class AService {
@PostConstruct
private void init() {
String threadName = Thread.currentThread().getName();
System.out.printf("线程号为%s,开始调用业务fun方法\n", threadName);
fun();
}
public void fun() {
String threadName = Thread.currentThread().getName();
System.out.printf("线程号为%s,开始处理业务\n", threadName);
}
}
启动应用即触发动作,控制台输出为:
线程名为main,开始调用业务fun方法
线程名为main,fun方法开始处理业务
完美!此时,你发现fun方法执行时间太长,需要做异步化处理。你就立马想到了使用Spring提供的@Async
注解轻松搞定:
@Async
public void fun() {
...
}
再次运行,控制台输出:
线程名为main,开始调用业务fun方法
线程名为main,fun方法开始处理业务
what?木有生效呀!这时你灵机一动,原因是没用开启该模块嘛。所以你迅速的使用@EnableAsync
注解启用Spring的异步模块,满怀期待的再次运行应用,控制台输出:
线程名为main,开始调用业务fun方法
线程名为main,fun方法开始处理业务
what a ...?怎么还是不行。你挠了挠头,想起来之前踩过的“事务不生效的坑”,场景和这类似,所以你模仿着采用了相同的方式来解决:自己注入自己(循环依赖)
@Autowired
private AService aService; // 自己注入自己
@PostConstruct
private void init() {
...
aService.fun(); // 通过代理对象调用而非this调用
}
这次满怀信心的再次运行,没想到,启动抛出BeanCurrentlyInCreationException
异常
org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'AService': Bean with name 'AService' has been injected into other beans [AService] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:649) ~[spring-beans-5.3.13.jar:5.3.13]
...
异常关键字:circular reference
循环引用!!!不是说好了允许循环引用的吗?怎么肥四?怎么破???
至此,笔者将此问题抛出,有兴趣的同学可思考一下问题根因、解决方案哈。最终的效果应该是不同线程异步执行的:
线程名为main,开始调用业务fun方法
线程名为task-1,fun方法开始处理业务
Tips:笔者在之前的文章里对此问题有过非常非常详细的叙述,感兴趣的可自行向前翻哈!!!主动学习
标签:springboot2.6,禁止,Spring,依赖,线程,引用,fun,main,循环 From: https://www.cnblogs.com/joeblackzqq/p/18036871