Java Spring循环依赖原理与bean的生命周期图文案例详解

yizhihongxing

Java Spring是一套开源的JavaEE框架,它的核心是IoC(控制反转)和AOP(面向切面编程)。在Spring中,循环依赖是一个比较重要的概念,本文将详细讲解Java Spring循环依赖原理与bean的生命周期。

什么是循环依赖

在Spring容器中,当Bean A依赖于Bean B,并且Bean B又依赖于Bean A时,我们就称这种情况为循环依赖。

例如:

public class A {
    private B b;
    public A(B b) {
        this.b = b;
    }
}

public class B {
    private A a;
    public B(A a) {
        this.a = a;
    }
}

这两个类之间就存在循环依赖。这种情况下,如果不进行特殊处理,Spring容器将无法实例化Bean A和Bean B。

Spring中的循环依赖解决方案

Spring容器中默认情况下是无法解决循环依赖的。但是,Spring提供了两种解决循环依赖的方案:构造函数注入和setter方法注入。

构造函数注入

Spring容器在创建Bean时,会调用Bean的构造函数进行实例化。如果一个Bean依赖另一个Bean,你可以通过构造函数注入的方式解决循环依赖问题。

但是,如果两个Bean互相依赖,并且都是通过构造函数注入方式实现依赖注入,Spring容器就无法解决循环依赖问题,抛出BeanCurrentlyInCreationException。

例如:

public class A {
    private B b;
    public A(B b) {
        this.b = b;
    }
}

public class B {
    private A a;
    public B(A a) {
        this.a = a;
    }
}

@Configuration
public class AppConfig {
    @Bean
    public A a() {
        return new A(b());
    }

    @Bean
    public B b() {
        return new B(a());
    }
}

上述代码中存在循环依赖,而且通过构造函数注入的方式实现依赖注入,Spring容器将抛出BeanCurrentlyInCreationException异常。

setter方法注入

除了构造函数注入外,还可以通过setter方法注入的方式解决循环依赖问题。在Spring容器中,当一个Bean依赖另一个Bean时,容器会先实例化依赖的Bean,然后通过setter方法注入方式将依赖的Bean注入到主Bean中。

例如:

public class A {
    private B b;
    public void setB(B b) {
        this.b = b;
    }
}

public class B {
    private A a;
    public void setA(A a) {
        this.a = a;
    }
}

@Configuration
public class AppConfig {
    @Bean
    public A a() {
        A a = new A();
        a.setB(b());
        return a;
    }

    @Bean
    public B b() {
        B b = new B();
        b.setA(a());
        return b;
    }
}

通过setter方法注入的方式解决循环依赖问题,可以避免BeanCurrentlyInCreationException异常的发生。

Bean的生命周期

在了解循环依赖的解决方案之前,需要先了解Spring中Bean的生命周期。Bean的生命周期可以分为以下5个步骤:

  1. 实例化(Instantiation):Spring容器根据Bean的定义信息创建Bean的实例。
  2. 属性赋值(Population):Spring容器将Bean的属性值通过setter方法或直接设置实例变量的方式赋值。
  3. 初始化(Initialization):当所有属性值完成注入后,Spring容器会调用Bean的初始化方法(如果定义了的话)。
  4. 就绪(Ready):在初始化方法调用后,Bean处于就绪状态,可以通过BeanFactory获取到实例。
  5. 销毁(Destruction):当容器关闭时,所有Bean实例都会被销毁,同时也会调用Bean的销毁方法(如果定义了的话)。

Spring循环依赖示例

下面通过一个实例来演示Spring中如何解决循环依赖问题。

首先,创建一个Person类,其中依赖于Dog类:

public class Person {
    private Dog dog;
    public Person(Dog dog) {
        this.dog = dog;
    }
    public void setDog(Dog dog) {
        this.dog = dog;
    }
    public void playWithDog() {
        System.out.println("play with " + dog.getName());
    }
}

在Person类中,通过构造函数注入方式依赖于Dog类。

接着,创建一个Dog类,其中依赖于Person类:

public class Dog {
    private Person person;
    public Dog() {}
    public void setPerson(Person person) {
        this.person = person;
    }
    public void playWithPerson() {
        System.out.println("play with " + person.getName());
    }
}

在Dog类中,通过setter方法注入方式依赖于Person类。

最后,创建一个配置类,将Person类和Dog类都注入到容器中:

@Configuration
public class AppConfig {
    @Bean
    public Person person() {
        return new Person(dog());
    }
    @Bean
    public Dog dog() {
        Dog dog = new Dog();
        dog.setPerson(person());
        return dog;
    }
}

在AppConfig中,先实例化Dog类,然后使用setter方法将Person类注入到Dog类中,最后再将Person类注入到容器中。

通过上述方式,就可以解决循环依赖问题。

综上所述,本文详细讲解了Java Spring循环依赖原理与bean的生命周期,同时提供了构造函数注入和setter方法注入两种解决循环依赖的方案,以及通过示例演示了Spring如何解决循环依赖问题。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java Spring循环依赖原理与bean的生命周期图文案例详解 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • Android消息推送:手把手教你集成小米推送(附demo)

    Android消息推送:手把手教你集成小米推送(附demo) 1. 注册小米开发者账号并创建应用 首先,访问小米开放平台,注册一个开发者账号。 登录后,在控制台中创建一个新的应用,并获取到应用的AppID和AppKey。 2. 集成小米推送SDK 在项目的build.gradle文件中添加小米推送SDK的依赖: dependencies { implemen…

    other 2023年10月13日
    00
  • 深入浅出学习AQS组件

    深入浅出学习AQS组件攻略 什么是AQS AQS (AbstractQueuedSynchronizer) 是 Java 并发包提供的一个用于构建锁和同步器的基础框架,是Java并发编程中重要的底层实现。 AQS的设计思想是对java.util.concurrent包所有同步器的公共行为进行抽象和封装,以便于在实现具体同步器(如ReentrantLock、S…

    other 2023年6月27日
    00
  • PostgreSQL 实现查询表字段信息SQL脚本

    PostgreSQL 是一个常用的关系型数据库系统,支持许多 SQL 操作,本文将介绍如何实现查询表字段信息 SQL 脚本的方法。 使用信息模式表查询表字段信息 PostgreSQL 中有一个名为 information_schema 的信息模式表,包含了所有的元数据信息,我们可以通过查询该表来获取指定表的字段信息。具体步骤如下: 使用 USE 命令选择相应…

    other 2023年6月25日
    00
  • 详解Spring 中如何控制2个bean中的初始化顺序

    要控制 Spring 中两个 Bean 的初始化顺序,我们需要使用两种方式: 使用 @DependsOn 注解 @DependsOn 注解可以定义 Spring 容器加载 Bean 的顺序,让 Bean 的初始化顺序按照我们的预期进行。只需要在需要定义执行顺序的 Bean 上加上 @DependsOn 注解,并在注解中指定需要依赖的 Bean 的名称即可实现…

    other 2023年6月20日
    00
  • Snagit for mac(截图软件)中文版,截个图就是这么容易!

    下面是关于Snagit for Mac截图软件的完整攻略,包括软件介绍、使用方法和两个示例等方面。 软件介绍 Snagit for Mac是一款功能强大的截图软件,它可以帮助用户快速、方便地进行屏幕截图、视频录制、图像编辑等操作。该软件具有简单易用、功能丰富、界面友好等特点,是Mac用户进行截图和录屏的首选工具。 使用方法 使用Snagit for Mac进…

    other 2023年5月6日
    00
  • jenkins可用的grafana模板

    Jenkins可用的Grafana模板 简介 Jenkins是一个流行的开源CI/CD工具,用于自动化构建、测试和部署应用程序。Grafana是一个数据可视化工具,用于创建漂亮的仪表盘并监控系统性能。本文将介绍如何创建Jenkins可用的Grafana模板,以监控其构建和测试的结果。 插件安装 在Jenkins服务器上安装Prometheus插件,以便将指标…

    其他 2023年3月28日
    00
  • IP地址自动修改的功能移植

    IP地址自动修改的功能移植攻略 简介 IP地址自动修改的功能移植是指将一个已经存在的IP地址自动修改的功能移植到另一个系统或应用程序中。这个功能可以用于自动更新网络设备的IP地址,提高网络管理的效率。下面是一个详细的攻略,包含了移植过程中的几个关键步骤和示例说明。 步骤 1. 确定目标系统和应用程序 首先,确定需要将IP地址自动修改功能移植到的目标系统和应用…

    other 2023年7月29日
    00
  • sqlserver行转列(pivot) 列转行(unpivot)总结

    SQL Server 行转列(Pivot)和列转行(Unpivot)总结 在SQL Server中,有时需要将一些行数据转换成列数据的方式呈现,或者将列数据转换成行数据的方式呈现,这就需要使用行转列和列转行的功能。 行转列(Pivot) 行转列是将多行数据转换成一行数据,对于这种需求,我们可以使用PIVOT函数。PIVOT函数将行数据转换成列数据,我们需要指…

    其他 2023年3月28日
    00
合作推广
合作推广
分享本页
返回顶部