0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

SpringBoot循环依赖的症状和解决方案

Android编程精选 来源:CSDN-熊猫Jay 2023-05-06 15:30 次阅读

什么是循环依赖?

循环依赖是指在Spring Boot 应用程序中,两个或多个类之间存在彼此依赖的情况,形成一个循环依赖链。

在这种情况下,当一个类在初始化时需要另一个类的实例,而另一个类又需要第一个类的实例时,就会出现循环依赖问题。这会导致应用程序无法正确地初始化和运行,因为Spring Boot 无法处理这种循环依赖关系。

问题及症状

在2.6.0之前,Spring Boot会自动处理循环依赖的问题。2.6.0及之后的版本会默认检查循环依赖,存在该问题则会报错。

ComponentA类注入ComponentB类,ComponentB类注入ComponentA类,就会发生循环依赖的问题。

ComponentA

importorg.springframework.stereotype.Service;
importjavax.annotation.Resource;

@Service
publicclassComponentA{

@Resource
privateComponentBcomponentB;

}

ComponentB

importorg.springframework.stereotype.Service;
importjavax.annotation.Resource;

@Service
publicclassComponentB{

@Resource
privateComponentAcomponentA;

}

错误

现在,2.6.0 这个版本已经默认禁止 Bean 之间的循环引用, 则基于上面的代码,会报错:

***************************
APPLICATIONFAILEDTOSTART
***************************

Description:

Thedependenciesofsomeofthebeansintheapplicationcontextformacycle:

┌─────┐
|componentA
↑↓
|componentB
└─────┘


Action:

Relyinguponcircularreferencesisdiscouragedandtheyareprohibitedbydefault.Updateyourapplicationtoremovethedependencycyclebetweenbeans.Asalastresort,itmaybepossibletobreakthecycleautomaticallybysettingspring.main.allow-circular-referencestotrue.

解决方法

循环依赖是指两个或更多的组件之间存在着互相依赖的关系。在Spring Boot应用程序中,循环依赖通常是由以下几种情况引起的:

构造函数循环依赖: 两个或更多的组件在它们的构造函数中互相依赖。

属性循环依赖: 两个或更多的组件在它们的属性中互相依赖。

方法循环依赖: 两个或更多的组件在它们的方法中互相依赖。

Spring Boot提供了一些解决循环依赖的方法:

构造函数注入: 在构造函数中注入依赖项,而不是在属性中注入。

Setter注入: 使用setter方法注入依赖项,而不是在构造函数中注入。

延迟注入: 使用@Lazy注解延迟加载依赖项。

@Autowired注解的required属性: 将required属性设置为false,以避免出现循环依赖问题。

@DependsOn注解: 使用@DependsOn注解指定依赖项的加载顺序,以避免出现循环依赖问题

构造器注入的案例

假设有以下两个类:

publicclassA{
privateBb;

publicA(){
//...
}

publicvoidsetB(Bb){
this.b=b;
}
}

publicclassB{
privateAa;

publicB(){
//...
}

publicvoidsetA(Aa){
this.a=a;
}
}

通过构造函数注入可以避免循环依赖,改造后的代码如下:

publicclassA{
privateBb;

publicA(Bb){
this.b=b;
}
}

publicclassB{
privateAa;

publicB(Aa){
this.a=a;
}
}

这样,在创建 A 实例时,只需要将 B 实例传递给 A 的构造函数即可,不需要再通过 setter 方法将 B 实例注入到 A 中。同理,在创建 B 实例时,只需要将 A 实例传递给 B 的构造函数即可,不需要再通过 setter 方法将 A 实例注入到 B 中。这样可以避免循环依赖。

延迟注入的案例

假设有如下情景:

类A依赖于类B,同时类B也依赖于类A。这样就形成了循环依赖。

为了解决这个问题,可以使用@Lazy注解,将类A或类B中的其中一个延迟加载。

例如,我们可以在类A中使用@Lazy注解,将类A延迟加载,这样在启动应用程序时,Spring容器不会立即加载类A,而是在需要使用类A的时候才会进行加载。这样就避免了循环依赖的问题。

示例代码如下:

@Component
publicclassA{

privatefinalBb;

publicA(@LazyBb){
this.b=b;
}

//...
}

@Component
publicclassB{

privatefinalAa;

publicB(Aa){
this.a=a;
}

//...
}

在类A中,我们使用了@Lazy注解,将类B延迟加载。这样在启动应用程序时,Spring容器不会立即加载类B,而是在需要使用类B的时候才会进行加载。

这样就避免了类A和类B之间的循环依赖问题。

接口隔离的案例

假设有两个类A和B,它们之间存在循环依赖:

publicclassA{
privatefinalBb;
publicA(Bb){
this.b=b;
}
}

publicclassB{
privatefinalAa;
publicB(Aa){
this.a=a;
}
}

这时候,如果直接在Spring Boot中注入A和B,就会出现循环依赖的问题。为了解决这个问题,可以使用接口隔离。

首先,定义一个接口,包含A和B类中需要使用的方法:

publicinterfaceService{
voiddoSomething();
}

然后,在A和B类中分别注入Service接口:

publicclassA{
privatefinalServiceservice;
publicA(Serviceservice){
this.service=service;
}
}

publicclassB{
privatefinalServiceservice;
publicB(Serviceservice){
this.service=service;
}
}

最后,在Spring Boot中注入Service实现类:

@Service
publicclassServiceImplimplementsService{
privatefinalAa;
privatefinalBb;
publicServiceImpl(Aa,Bb){
this.a=a;
this.b=b;
}
@Override
publicvoiddoSomething(){
//...
}
}

通过这种方式,A和B类不再直接依赖于彼此,而是依赖于同一个接口。同时,Spring Boot也能够正确地注入A、B和ServiceImpl,避免了循环依赖的问题。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 接口
    +关注

    关注

    33

    文章

    8474

    浏览量

    150772
  • 函数
    +关注

    关注

    3

    文章

    4299

    浏览量

    62374
  • 应用程序
    +关注

    关注

    37

    文章

    3238

    浏览量

    57571
  • spring
    +关注

    关注

    0

    文章

    338

    浏览量

    14301
  • Boot
    +关注

    关注

    0

    文章

    149

    浏览量

    35766
  • SpringBoot
    +关注

    关注

    0

    文章

    173

    浏览量

    165

原文标题:SpringBoot 循环依赖的症状和解决方案

文章出处:【微信号:AndroidPush,微信公众号:Android编程精选】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    2009最新LED路灯技术设计和解决方案

    2009年11月19-20日,OFweek光电新闻网,LEDWeekly将举办“2009最新LED路灯技术设计和解决方案”系列在线研讨会。欢迎朋友们参加, 详细情况看这里~: http://webinar.ofweek.com/index.action?user.id=2 有兴趣的朋友可以来参加! 
    发表于 11-08 23:57

    仪表放大器--常见的应用问题和解决方案

    仪表放大器--常见的应用问题和解决方案很完整的资料!
    发表于 12-15 09:53

    无线传感器网络的挑战和解决方案

    无线传感器网络的挑战和解决方案
    发表于 09-17 06:53

    EMI耦合类型和解决方案

    、高性能和解决方案尺寸三个考虑因素通常相互冲突:只能优先考虑一两个,而放弃第三个,尤其当设计期限临近时。牺牲一些性能变得司空见惯;其实不应该是这样的。。
    发表于 10-22 14:10

    SpringBoot 学习笔记

    SpringBoot 学习笔记 【整合JWT】添加依赖创建工具类登录获取jwt使用jwtDemo源码参考资料添加依赖pom.xml...com.auth0java-jwt3.12.0
    发表于 07-01 07:27

    springboot集成mqtt

    springboot集成mqtt,大纲一.数据入库1.数据入库解决方案二.开发实时订阅发布展示页面1.及时通讯技术2.技术整合
    发表于 07-16 07:53

    ADI锂电池测试设备和解决方案

    ADI锂电池测试设备和解决方案
    发表于 09-08 16:23 15次下载
    ADI锂电池测试设备<b class='flag-5'>和解决方案</b>

    PFC+LLC的产品和解决方案分析

    PFC LLC英雄产品和解决方案
    的头像 发表于 05-29 09:05 1w次阅读
    PFC+LLC的产品<b class='flag-5'>和解决方案</b>分析

    Java:调用window的matlab遇到的问题和解决方案

    Java:调用window的matlab遇到的问题和解决方案
    的头像 发表于 06-20 09:32 3305次阅读
    Java:调用window的matlab遇到的问题<b class='flag-5'>和解决方案</b>

    无线传感器网络的挑战和解决方案

    无线传感器网络的挑战和解决方案
    发表于 03-19 04:28 4次下载
    无线传感器网络的挑战<b class='flag-5'>和解决方案</b>

    AN-1429: 手机中耳机驱动的设计考虑和解决方案

    AN-1429: 手机中耳机驱动的设计考虑和解决方案
    发表于 03-20 13:06 7次下载
    AN-1429: 手机中耳机驱动的设计考虑<b class='flag-5'>和解决方案</b>

    无线传感器网络的挑战和解决方案

    无线传感器网络的挑战和解决方案
    发表于 03-21 13:41 1次下载
    无线传感器网络的挑战<b class='flag-5'>和解决方案</b>

    高可靠性组件和解决方案

    高可靠性组件和解决方案
    发表于 04-26 14:38 6次下载
    高可靠性组件<b class='flag-5'>和解决方案</b>

    关于Spring的循环依赖问题

      Spring 的循环依赖,源码详细分析 → 真的非要三级缓存吗 中讲到了循环依赖问题
    的头像 发表于 06-14 17:21 1726次阅读

    PCB金手指设计的常见问题和解决方案

    PCB金手指设计的常见问题和解决方案
    的头像 发表于 12-25 10:09 2068次阅读