Spring循环依赖的处理方法

 更新时间:2023年08月23日 11:17:06   作者:去码头整点薯条​⁢⁢⁢⁡  
循环依赖是指两个或多个组件之间相互依赖,形成一个闭环,从而导致这些组件无法正确地被初始化或加载,这篇文章主要介绍了Spring循环依赖的处理,需要的朋友可以参考下

循环依赖是指两个或多个组件之间相互依赖,形成一个闭环,从而导致这些组件无法正确地被初始化或加载。这种情况可能会在软件开发中引起问题,因为循环依赖会导致初始化顺序混乱,组件之间的关系变得复杂,甚至可能引发死锁或其他不稳定行为。

在编程中,循环依赖通常出现在模块、类、或者组件之间的相互引用上,导致编译、加载或初始化过程中的问题。在依赖注入(DI)框架中,循环依赖可能会导致对象的创建和初始化失败。

@Service
public class TestService1 {
    @Autowired
    private TestService2 testService2;
    public void test1() {
    }
}
@Service
public class TestService2 {
    @Autowired
    private TestService1 testService1;
    public void test2() {
    }
}

A 依赖于 B,而 B 也依赖于 A,形成了循环依赖。如果没有适当的处理,初始化这两个类的实例可能会导致问题。这段代码之所以能正常运行,是因为Spring内部机制,解决了循环依赖的问题。

Spring内部有三级缓存

  • singletonObjects 一级缓存,用于保存实例化、注入、初始化完成的bean实例
  • earlySingletonObjects 二级缓存,用于保存实例化完成的bean实例
  • singletonFactories 三级缓存,用于保存bean创建工厂,以便于后面扩展有机会创建代理对象。

Spring解决循环依赖步骤:

  • Bean 的注册:首先,Spring会解析并注册所有的Bean定义,但不会立即创建Bean的实例。
  • 提前创建 Bean 实例:对于每个要创建的单例( @Service 默认是单例作用域),Spring会提前创建一个半初始化的实例,并将其放入 singletonFactories 缓存中。这是为了解决循环依赖问题。
  • 开始创建 TestService1:当开始创建 TestService1 时,发现它依赖于 TestService2 。因为 TestService2 的半初始化实例已经在 singletonFactories 缓存中,所以会使用该实例创建 TestService1 ,并在 singletonFactories 缓存中移除 TestService2 的工厂。
  • 开始创建 TestService2:当创建 TestService2 时,发现它依赖于 TestService1 ,但由于 TestService1 的半初始化实例已经存在,所以会使用该实例创建 TestService2 ,并在 singletonFactories 缓存中移除 TestService1 的工厂。
  • 完全初始化:一旦创建过程完成,Spring会执行 TestService1 TestService2 的初始化操作,包括注入和其他初始化方法。这将使它们变成完全初始化的Bean

图解:

循环依赖可能出现的场景

  • 模块之间的相互引用:在模块化的软件设计中,不同模块之间可能会相互引用,特别是当模块之间存在交叉的功能需求或依赖时。如果模块之间的依赖关系没有正确管理,就可能产生循环依赖。
  • 类的相互引用:在面向对象编程中,不同类之间可能会有相互引用,尤其是在它们之间存在双向的依赖关系时。如果类的构造函数或方法参数中出现了相互引用,就可能导致循环依赖问题。
  • 依赖注入框架配置不当:依赖注入框架(如Spring)用于管理组件之间的依赖关系。如果配置文件中出现了循环依赖,框架可能无法正确初始化对象,导致异常。
  • 事件和消息驱动的系统:在事件和消息驱动的系统中,不同组件可能通过事件或消息进行通信。如果事件的发起者和接收者之间出现相互依赖,就可能导致循环依赖。
  • 单例模式的使用:当使用单例模式时,如果多个单例对象之间相互依赖,可能会形成循环依赖。单例对象在整个应用程序中只有一个实例,因此其依赖关系需要特别注意。
  • 构建和初始化顺序问题:在某些情况下,对象的构建和初始化顺序可能导致循环依赖。如果某个对象在构建阶段需要引用另一个对象,而后者又需要在构建阶段引用前者,就可能形成循环依赖。

如何解决循环依赖

  • 重构设计:重新审视组件之间的关系,尝试将循环依赖问题转化为单向的依赖关系。这可能需要重新划分模块或类的职责,以减少相互依赖。
  • 引入接口或抽象类:通过引入接口或抽象类,可以将具体的依赖关系替换为更高层次的抽象依赖,从而解耦循环依赖。
  • 延迟初始化:将对象的初始化推迟到实际使用它们的时候,以避免在初始化阶段出现循环依赖。这可以通过懒加载等方式来实现。
  • 使用中介者模式:引入中介者或事件系统,将类之间的通信转移到中介者中,从而降低直接的循环依赖。这可以将相互依赖的关系集中在一个地方进行处理。
  • 使用依赖注入容器:依赖注入框架(如Spring)可以处理循环依赖问题。这些框架使用一些特殊的策略,以确保对象的正确初始化顺序,从而解决循环依赖。
  • 通过Setter注入或后处理器解决:在某些情况下,通过使用Setter方法注入依赖或使用依赖后处理器可以解决循环依赖问题。这样,对象的构建和初始化可以分为多个步骤。
  • 更改对象创建时机:有时,将对象的创建从构造函数移至其他方法中,可以避免在构造函数阶段引发循环依赖。
  • 设计模式:一些设计模式,如工厂方法模式、抽象工厂模式,可以用来分离对象的构建和初始化,从而避免循环依赖。

到此这篇关于Spring循环依赖的处理的文章就介绍到这了,更多相关Spring循环依赖内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 关于Java中的mysql时区问题详解

    关于Java中的mysql时区问题详解

    这篇文章主要给大家介绍了关于Java中mysql时区问题的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Java具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2020-05-05
  • Java实现多层文件夹压缩功能

    Java实现多层文件夹压缩功能

    这篇文章主要为大家详细介绍了如何利用Java语言进行多层文件夹压缩功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-08-08
  • 基于Spring实现零重启自由编排任务的定时管理器

    基于Spring实现零重启自由编排任务的定时管理器

    我们发现,我们使用Spring自带的定时任务如果要有修改,那么就要修改代码,然后重启项目,所以本文就带大家实现一个零重启自由编排任务的定时管理器吧
    2023-07-07
  • Java前端开发框架实现的流程和代码示例

    Java前端开发框架实现的流程和代码示例

    我们可以实现一个Java前端开发框架,这个框架包含了初始化、组件渲染、组件更新、事件监听和事件触发等功能,希望这个指南能够对刚入行的小白有所帮助
    2023-10-10
  • Spring实战之Qualifier注解用法示例

    Spring实战之Qualifier注解用法示例

    这篇文章主要介绍了Spring实战之Qualifier注解用法,结合实例形式详细分析了spring Qualifier注解相关配置、定义与使用方法,需要的朋友可以参考下
    2019-12-12
  • java后台判断客户端是手机/PC并返回不同页面的实例

    java后台判断客户端是手机/PC并返回不同页面的实例

    下面小编就为大家分享一篇java后台判断客户端是手机/PC并返回不同页面的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-01-01
  • Spring Boot中优雅地处理参数传递的技巧分享

    Spring Boot中优雅地处理参数传递的技巧分享

    最近一直在学习Spring Boot,今天将其中的从前台过来的参数传递总结一下,下面这篇文章主要给大家介绍了关于Spring Boot中优雅地处理参数传递的技巧,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-05-05
  • Java基础学习之构造方法详解

    Java基础学习之构造方法详解

    这篇文章主要为大家详细介绍了Java基础学习中构造方法的概述及注意事项,文中的示例代码讲解详细,对我们学习Java有一定帮助,需要的可以参考一下
    2022-08-08
  • SpringBoot整合Mybatis Plus多数据源的实现示例

    SpringBoot整合Mybatis Plus多数据源的实现示例

    本文主要介绍了SpringBoot整合Mybatis Plus多数据源的实现示例,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • Netty学习教程之Netty与Marshalling结合发送对象

    Netty学习教程之Netty与Marshalling结合发送对象

    Netty是由JBOSS提供的一个Java开源框架,之前已经给大家简单介绍了一些基础与使用,下面这篇文章主要给大家介绍了关于Netty与Marshalling结合发送对象的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-05-05

最新评论