代码之前存在循环依赖,未报错,但是加入新的代码之后出现了循环依赖报错

经历过一次循环依赖报错,背景:
新加了一段代码,然后被提示循环依赖报错,才发现有两个service相互注入.
** 定位:发现只要注释掉@Async就不报错了**

问题一: 为什么之前就循环依赖了但是没报错
问题二: 什么引起的循环依赖报错

解释一:
Spring内部解决机制:Spring框架对于默认单例(singleton)的Bean提供了循环依赖的解决机制。它通过使用三级缓存(包括单例池、早期暴露对象和可以生成Bean的工厂)来解决单例Bean之间的属性注入循环依赖问题。在Bean的创建过程中,如果一个Bean引用了另一个尚未完全初始化的Bean,Spring会尝试使用缓存中的早期暴露对象或工厂来完成依赖注入,从而避免循环依赖导致的错误

解释二:
@Async注解在Spring框架中用于创建异步执行的方法。当@Async导致循环依赖报错时,其根本原因通常与Spring容器管理Bean的生命周期和异步执行机制有关。

以下是导致循环依赖报错的具体原因分析:

异步方法执行机制:@Async注解的方法会在一个单独的线程中异步执行。Spring为了支持异步方法,通常会为这些方法创建一个代理对象,该代理对象负责在需要时启动新线程来执行异步方法。

Bean的创建与依赖注入:在Spring容器启动过程中,会按照配置的顺序创建并初始化Bean。如果两个或多个Bean相互依赖对方,并且这些依赖关系发生在Bean的创建过程中(即构造器注入或字段注入),Spring会尝试解决这种循环依赖。但是,由于异步方法的特性,Spring在创建代理对象时可能会遇到额外的复杂性。

代理对象的创建:当Spring检测到@Async注解时,它会为该方法所在的Bean创建一个代理对象。这个代理对象会在需要调用异步方法时启动新线程。如果另一个Bean依赖于这个异步Bean的代理对象,并且这个依赖关系是在Bean的创建过程中建立的,那么可能会出现循环依赖的问题。

循环依赖检测:Spring容器在创建Bean时会检测循环依赖。对于普通的Bean,Spring能够解决构造器注入或字段注入导致的循环依赖问题。但是,由于异步代理对象的创建时机和方式与普通Bean不同,Spring可能无法正确地处理涉及异步代理对象的循环依赖。

容器启动顺序问题:有时候,循环依赖问题可能是由于Bean的初始化顺序不当造成的。例如,如果异步Bean依赖于另一个尚未初始化的Bean,或者它们的初始化顺序与期望的不符,那么可能会导致循环依赖错误。

综上所述,@Async导致循环依赖报错的原因主要是异步方法的执行机制与Spring容器管理Bean的生命周期之间的不匹配。为了避免这种问题,应该仔细设计应用程序的架构,确保Bean之间的依赖关系清晰且合理,并尽可能避免在Bean的创建过程中引入循环依赖。如果确实需要异步执行,可以考虑使用其他方式来解耦,例如使用消息队列、事件驱动等方式来实现异步通信。

上面是AI给的回答

个人理解: 由于该@Async注解会创建代理对象,代理对象初始化的时候需要去解析依赖,此时依赖存在循环,所以报错

根据这个原因,拓展: @Scheduled 定时任务,也会创建一个代理(已测试,会报错)

我的解决: 自己重新建一个service,把新的代码移到没有循环依赖的service中即可继续使用@Asycn

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值