自学内容网 自学内容网

spring循环依赖以及MyBatis-Plus的继承特性导致循环依赖自动解决失效

在 Spring 中,循环依赖是指两个或多个 bean 之间相互依赖,形成一个循环引用的情况。Spring 对于循环依赖有一定的处理机制,但也存在一些限制。

一、Spring 处理循环依赖的方式

  1. 三级缓存解决构造函数注入的循环依赖

    • Spring 首先创建一个正在创建中的 bean 对象,并将其放入一个 “正在创建的 bean 缓存”(一级缓存)中。
    • 当遇到循环依赖时,Spring 会尝试从 “正在创建的 bean 缓存” 中获取 bean 对象,如果获取到,则说明循环依赖已经被解决。
    • 如果在 “正在创建的 bean 缓存” 中没有找到 bean 对象,Spring 会从 “早期单例对象缓存”(二级缓存)中获取 bean 对象。如果获取到,则说明该 bean 对象已经被创建,并且是一个单例对象,可以直接返回。
    • 如果在 “早期单例对象缓存” 中也没有找到 bean 对象,Spring 会从 “单例对象缓存”(三级缓存)中获取 bean 对象。如果获取到,则说明该 bean 对象已经被创建,并且是一个单例对象,可以直接返回。
  2. setter 注入的循环依赖处理

    • Spring 在处理 setter 注入的循环依赖时,会先创建 bean 对象,然后再设置其依赖的属性。
    • 当遇到循环依赖时,Spring 会先创建一个 bean 对象,并将其放入 “正在创建的 bean 缓存” 中。然后,Spring 会尝试从 “正在创建的 bean 缓存” 中获取依赖的 bean 对象。如果获取到,则说明循环依赖已经被解决。如果没有获取到,则继续创建依赖的 bean 对象,并将其放入 “正在创建的 bean 缓存” 中。

二、Spring 处理循环依赖的限制

  1. 构造函数注入的限制

    • 如果循环依赖中的 bean 对象是通过构造函数注入的,并且构造函数中存在循环依赖的参数,那么 Spring 无法解决这种循环依赖。
    • 例如,如果有两个 bean 对象 A 和 B,A 的构造函数中依赖 B,B 的构造函数中依赖 A,那么 Spring 无法创建这两个 bean 对象。
  2. 原型 bean 的限制

    • Spring 对于原型(prototype)bean 的循环依赖无法处理。
    • 原型 bean 每次请求都会创建一个新的实例,因此无法在创建过程中解决循环依赖。

三、解决循环依赖的方法

  1. 重构代码

    • 检查代码中的循环依赖关系,尝试通过重构代码来消除循环依赖。
    • 可以将循环依赖的部分提取到一个单独的 bean 中,或者使用依赖注入的替代方法,如 setter 注入或方法注入。
  2. 使用 @Lazy 注解

    • 在循环依赖的 bean 中,可以使用@Lazy注解来延迟加载依赖的 bean。
    • 这样,当 Spring 创建 bean 对象时,不会立即创建依赖的 bean 对象,而是在需要时才创建。
    • 这种方法可以在一定程度上解决循环依赖问题,但需要注意的是,使用@Lazy注解可能会影响性能,因为依赖的 bean 对象只有在需要时才会被创建。
  3. 使用 @DependsOn 注解

    • @DependsOn注解可以指定一个 bean 的初始化顺序。
    • 在循环依赖的情况下,可以使用@DependsOn注解来确保一个 bean 在另一个 bean 之前被初始化。
    • 例如,如果有两个 bean 对象 A 和 B,A 的初始化依赖于 B,那么可以在 A 的类上使用@DependsOn("B")注解,确保 B 在 A 之前被初始化。

总之,Spring 对于循环依赖有一定的处理机制,但也存在一些限制。在实际应用中,应该尽量避免循环依赖的情况发生,如果无法避免,可以通过重构代码、使用@Lazy注解或@DependsOn注解等方法来解决循环依赖问题。

四、MyBatis-Plus的继承特性导致循环依赖(Spring的三级缓存机制无法正常工作)

在使用MyBatis-Plus时,服务实现类(如PXXServiceImpl)通常会继承ServiceImpl类,并实现对应的服务接口(如IPXXService)。这种继承关系可能会导致Spring在创建Bean时遇到循环依赖的问题


Spring的三级缓存机制:Spring的三级缓存机制主要解决的是字段注入(Field Injection)或setter方法注入(Setter Injection)引起的循环依赖问题。对于构造函数注入(Constructor Injection),Spring无法解决循环依赖,因为构造函数注入要求所有依赖在Bean创建时必须是可用的


MyBatis-Plus的Bean包装:有观点认为,由于Service集成了MyBatis-Plus的基类,Spring可能将其视为“包装过的类”,这可能导致Spring的三级缓存机制无法正常工作,从而引发循环依赖问题。

解决方案
使用@Lazy注解:在Spring中,可以通过在注入的字段上添加@Lazy注解来延迟Bean的加载,这样可以避免循环依赖的问题。

抽象中间Service:可以通过创建一个中间Service层来避免直接的循环依赖,这样可以减少直接的依赖关系,从而避免循环依赖。

使用Setter方法注入:而不是字段注入或构造函数注入,Setter方法注入可以更好地与Spring的三级缓存机制配合,解决循环依赖问题。

重新设计架构:如果可能,重新设计服务层的架构,减少服务之间的直接依赖,或者将一些共用的服务抽象出来,以减少循环依赖的可能性。

综上所述,MyBatis-Plus的继承特性和Spring的Bean包装可能导致Spring的三级缓存机制无法完全解决循环依赖问题。您可以尝试上述解决方案来避免或解决循环依赖问题。


原文地址:https://blog.csdn.net/jakeswang/article/details/144011128

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!