springboot配置允许循环依赖问题

 更新时间:2023年05月19日 14:36:15   作者:keep one's resolveY  
这篇文章主要介绍了springboot配置允许循环依赖问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

springboot配置允许循环依赖

循环依赖报错

当启动项目时,可能出现程序不能启动的情况,查看调试日志

会提示 :

The dependencies of some of the beans in the application context form a cycle...

原因

SpringBoot 从 2.6 开始默认不允许出现 Bean 循环引用。而且这个是在Bean 定义上也就是类上就不允许出现循环引用。

解决方式       

1、允许循环引用存在               

方式1.在全局配置文件设置允许循环引用存在:

spring:
  main:
    allow-circular-references:true      

方式2.在SpringApplicationBuilder 添加设置允许循环引用:

public static void main(String[] args) {
  new SpringApplicationBuilder(DemoApplication.class).allowCircularReferences(true).run(args);
}        

2、消除循环依赖               

Spring官方的初心是不希望开发者编写循环引用的代码,也就是说未来的某个版本可能强制不能使用循环引用,因此在项目中消除循环依赖是不得不面对的问题。

面试官:”Spring是如何解决的循环依赖?“

答:Spring通过三级缓存解决了循环依赖,其中一级缓存为单例池(singletonObjects),二级缓存为早期曝光对象earlySingletonObjects,三级缓存为早期曝光对象工厂(singletonFactories)。

当A、B两个类发生循环引用时,在A完成实例化后,就使用实例化后的对象去创建一个对象工厂,并添加到三级缓存中,如果A被AOP代理,那么通过这个工厂获取到的就是A代理后的对象,如果A没有被AOP代理,那么这个工厂获取到的就是A实例化的对象。

当A进行属性注入时,会去创建B,同时B又依赖了A,所以创建B的同时又会去调用getBean(a)来获取需要的依赖,此时的getBean(a)会从缓存中获取,第一步,先获取到三级缓存中的工厂;第二步,调用对象工工厂的getObject方法来获取到对应的对象,得到这个对象后将其注入到B中。

紧接着B会走完它的生命周期流程,包括初始化、后置处理器等。当B创建完后,会将B再注入到A中,此时A再完成它的整个生命周期。至此,循环依赖结束!

面试官:”为什么要使用三级缓存呢?二级缓存能解决循环依赖吗?“

答:如果要使用二级缓存解决循环依赖,意味着所有Bean在实例化后就要完成AOP代理,这样违背了Spring设计的原则,Spring在设计之初就是通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来在Bean生命周期的最后一步来完成AOP代理,而不是在实例化后就立马进行AOP代理。

SpringBoot禁用循环依赖

Spring的Bean管理,一直是整个体系中津津乐道的东西。尤其是Bean的循环依赖,更是很多面试官最喜欢考察的2B知识点之一。

但事实上,项目中存在Bean的循环依赖,是代码质量低下的表现。多数人寄希望于框架层来给擦屁股,造成了整个代码的设计越来越糟,最后用一些奇技淫巧来填补犯下的错误。

还好,SpringBoot终于受不了这种滥用,默认把循环依赖给禁用了!

从2.6版本开始,如果你的项目里还存在循环依赖,SpringBoot将拒绝启动!

验证代码小片段

为了验证这个功能,我们只需要两段小代码。

CircularDependencyA.java

@Component
@RequiredArgsConstructor
public class CircularDependencyA {
    private final CircularDependencyB circB;
}

CircularDependencyB.java

@Component
@RequiredArgsConstructor
public class CircularDependencyB {
    private final CircularDependencyA circA;
}

RequiredArgsConstructor注解,是lombok包里面的,用来实现简单的构造器注入。不出所料,当我们启动代码的时候,报错了~~

报错如下:

The dependencies of some of the beans in the application context form a cycle:
┌─────┐
|  circularDependencyA defined in file [cir/CircularDependencyA.class]
↑     ↓
|  circularDependencyB defined in file [cir/CircularDependencyB.class]
└─────┘
 
Action:
 
Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.

当然,有些鸟人已经玩大了,循环依赖到处都是,改代码变的越来越不现实。那你还可以通过在yaml里配置参数来临时开启循环依赖。

spring.main.allow-circular-references=true

看来SpringBoot对恶势力的容忍能力还是不够坚决啊!

绕过SpringBoot这个拦截的方法不止一种,比如使用@Lazy注解进行延迟初始化。但这些都是治标不治本,辜负了SpringBoot的一片苦心。

做对的事

其实,我们一直把代码往下找下去,会发现这个开关,其实是Spring的功能。

AbstractAutowireCapableBeanFactory#allowCircularReferences
/** Whether to automatically try to resolve circular references between beans. */
private boolean allowCircularReferences = true;

很长一段时间,SpringBoot这个值都是默认为true的。但这种纵容造成了大批低质量的代码产生,以至于新员工一直在给老员工擦屁股。

把这个值默认设置为false,是坚持做对的事情。起码,在工程师编写出质量不高的代码时,能够知道他自己在做什么,而不是把隐患一步步的推迟,任代码腐败。

不得不为SpringBoot点个赞。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 详解使用Spring MVC统一异常处理实战

    详解使用Spring MVC统一异常处理实战

    本篇文章主要介绍了详解使用Spring MVC统一异常处理实战,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-04-04
  • Spring中的父子容器原理解析

    Spring中的父子容器原理解析

    这篇文章主要为大家介绍了Spring中的父子容器原理解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07
  • java图片和文本同时提交到表单的实例代码

    java图片和文本同时提交到表单的实例代码

    在本篇文章里小编给大家整理的是关于java实现图片和文本同时提交到表单的相关内容,有需要的朋友们可以学习下。
    2020-02-02
  • spring boot 配置freemarker及如何使用freemarker渲染页面

    spring boot 配置freemarker及如何使用freemarker渲染页面

    springboot中自带的页面渲染工具为thymeleaf 还有freemarker这两种模板引擎,本文重点给大家介绍spring boot 配置freemarker及如何使用freemarker渲染页面,感兴趣的朋友一起看看吧
    2023-10-10
  • java多线程文件下载器的实现

    java多线程文件下载器的实现

    本文主要介绍了java多线程文件下载器的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-11-11
  • SpringCloud Feign如何在远程调用中传输文件

    SpringCloud Feign如何在远程调用中传输文件

    这篇文章主要介绍了SpringCloud Feign如何在远程调用中传输文件,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09
  • HTTP 415错误-Unsupported media type详解

    HTTP 415错误-Unsupported media type详解

    这篇文章主要介绍了HTTP 415错误-Unsupported media type详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • Java Springboot的目的你知道吗

    Java Springboot的目的你知道吗

    在本篇文章中小编给大家分析了Java中Spring Boot的优势以及相关知识点内容,兴趣的朋友们可以学习参考下,希望能够给你带来帮助
    2021-09-09
  • 聊聊spring @Transactional 事务无法使用的可能原因

    聊聊spring @Transactional 事务无法使用的可能原因

    这篇文章主要介绍了spring @Transactional 事务无法使用的可能原因,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • Java超详细分析讲解哈希表

    Java超详细分析讲解哈希表

    哈希表是一种根据关键码去寻找值的数据映射结构,该结构通过把关键码映射的位置去寻找存放值的地方,说起来可能感觉有点复杂,我想我举个例子你就会明白了,最典型的的例子就是字典
    2022-06-06

最新评论