首页 > 其他分享 >Spring循环依赖+案例解析

Spring循环依赖+案例解析

时间:2024-07-31 12:49:56浏览次数:9  
标签:依赖 创建 bean 案例 Bean 实例 Spring 解析

什么是Spring中的循环依赖?

循环依赖是指两个或者多个bean互相依赖对方,从而形成一个闭环。例如:Bean A依赖于Bean B,而Bean B又依赖于Bean A。可能会导致Spring在尝试创建这些bean实例时出现问题,因为他们互相等待对方被创建,最终导致应用程序无法启动。

Spring是如何发现这种循环依赖的问题的呢?

通过依赖图来检测和发现循环依赖问题。如下步骤:

1 Bean的创建过程

Spring容器在启动时,会扫描配置文件(appliactionContext.xml)或者注解定义的bean,并且尝试创建这些bean的实例。创建bean实例的过程如下

  • 实例化:创建bean的实例。
  • 属性填充:为bean注入依赖其他的bean。
  • 初始化:执行自定义的初始化方法。

2 依赖注入过程

在属性填充阶段,Spring会为每个bean注入他所依赖的bean。在这个过程中,Spring会跟踪哪些bean正在被创建,以便检测循环依赖。

3 循环依赖检测机制

Spring通过一个名为“DefaultSingletonBeanRegistry”的类来跟踪单例bean的创建状态。该类维护了三个主要的缓存来管理bean的创建过程。

  • singletonObjects:一级缓存(存储完全初始化好的bean)
  • earlySingletonObjects:二级缓存(存储早期暴露的单例bean,用于解决循环依赖)
  • singletonFactories:三级缓存(存储用于创建bean实例的工厂)

具体的检测步骤

实例化阶段

当Spring开始实例化一个bean时,它会将这个bean标记为正在创建。这一步是通过将bean名称添加到一个“正在创建中的bean”集合(‘singletonCurrentlyInCreaontion’)中来实现的。

属性填充阶段

在属性填充阶段,Sping会为该bean注入其依赖的其他的bean。此时Spring会检查这个“其他的bean”是否已经在创建过程中。

  • 如果依赖的bean已经在创建中,Spring会检测到循环依赖,并根据不同的注入方式采取不同的处理方式。
  • 如果是构造函数注入,Spring会抛出‘BeanCurrentlyInCreationException’,因为无法解决构造函数中注入的循环依赖。
  • 如果是Setter注入,Spring会从‘earlySingletonObjects’或‘singletonFactories’中获取依赖的bean,提前暴露一个部分创建的bean引用来解决循环依赖。

举例

如Bean A和Bean B循环依赖

@Component
public class A {
    @Autowired
    private B b;

    public A() {
        System.out.println("A is created");
    }
}

@Component
public class B {
    @Autowired
    private A a;

    public B() {
        System.out.println("B is created");
    }
}

Spring的依赖注入过程:
1 实例化Bean A

  • 将Bean A 标记为正在创建,并添加到‘singletonCurrentlyInCreation’集合中。
  • 实例化Bean A,并将其放入到三级缓存‘singletonFactories’中。(三级缓存存放的是创建实例化的bean工厂)

2 填充Bean A的属性

  • 此时发现Bean A依赖Bean B ,于是开始创建Bean B。
  • 将Bean B标记为正在创建,并放入到‘singletonCurrentlyInCreation’集合中。
  • 实例化Bean B,并将其放入到三级缓存‘singletonFactories’中。

3 填充Bean B的属性

  • 发现Bean B依赖于Bean A 。此时,检查到Bean A 已经在创建过程中,因此发现了循环依赖。
  • 由于是Setter方法注入,Spring会从三级缓存‘singletonFactories’中获取一个部分创建的Bean A实例,提前暴露出来,放入二级缓存‘earlySingletonObjects’中。
  • 使用这个部分创建出来的Bean A实例 来填充Bean B的属性。

4 完成Bean B的创建

  • Bean B中的所有属性填充完毕后,Spring将Bean B的实例从三级缓存‘singletonFactories’中移到一级缓存‘singletonObjects’完全初始化好的bean中。

5 回到Bean A的创建

  • 继续为Bean A填充属性,此时可以从一级缓存‘singletonObejcts’中获取到完整的Bean B实例。
  • 完成Bean A的创建,并将其从三级缓存‘singletonFactories’中移到一级缓存‘singletonObjects’中。

标签:依赖,创建,bean,案例,Bean,实例,Spring,解析
From: https://www.cnblogs.com/kuangsun125/p/18334402

相关文章

  • 【计算机毕设论文】基于SpringBoot的家教管理系统-教师端
    ......
  • 【计算机毕设论文】基于SpringBoot的诗词管理系统
    ......
  • 使用宝塔对程序、依赖、配置文件分离的springboot项目进行部署运行
    spingboot中的依赖:<plugins><!--上线部署JAR启动分离依赖lib和配置--><!--打包jar--><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId>......
  • 学习笔记 String类案例练习 1.模拟用户登录 2.统计字符串英文字母大小写及数字个数
    目录案例一模拟用户登录需求:代码: 案例二统计字符串英文字母大小写及数字个数需求:代码:案例一模拟用户登录需求:已知正确的用户名和密码,请用程序实现模拟用户登录。总共给三次机会,登录之后,给出相应的提示代码:publicstaticvoidmain(String[]args){......
  • Android开发 - (适配器)Adapter类中ArrayAdapter实现类详细解析
    作用将数组数据映射到UI组件(如ListView、Spinner等)上的角色。它是BaseAdapter的一个子类,专门用于处理简单的数据集合,如数组或列表。ArrayAdapter简化了数据到视图映射的过程,使得开发者能够以更少的代码实现数据的展示。它的主要作用为以下几点:数据绑定:它能够将一组数据......
  • Spring-transaction 事务
    1.事务介绍1.1简介事务,就是一组操作数据库的动作集合。事务是现代数据库理论中的核心概念之一。如果一组处理步骤或者全部发生或者一步也不执行,我们称该组处理步骤为一个事务。当所有的步骤像一个操作一样被完整地执行,我们称该事务被提交。由于其中的一部分或多步执行失败,导致......
  • MQTT原理及案例
    MQTT协议是当今世界上最受欢迎的物联网协议,没有之一。MQTT协议为设备提供了稳定、可靠、简单易用的通信基础,截至目前通过MQTT协议连接的设备已经过亿,广泛应用于IoT、M2M等领域。本篇将从最基础的知识开始,向您讲解MQTT协议的原理与应用。目前MQTT主流版本有MQTT3.1.1......
  • 适用于 JDK 1.8 的 Spring Boot 的 maven 的 pom.xml 模板
    适用于JDK1.8的SpringBoot的maven的pom.xml模板 <?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:sche......
  • 解决非Spring Bean访问Spring Bean的问题:实用指南
    在非SpringBean类里获取SpringBean,会是什么情况?case1下面这段代码中,PlainClass表示一个普通Java类:publicclassPlainClass{publicvoidfoo1(){TheOtherBeanbean=SpringContextUtils.getBean(TheOtherBean.class);System.out.println(bean);......
  • SpringIoC-依赖注入源码解析
    目录1.依赖注入底层原理流程图2.Spring中到底有几种依赖注入的方式?2.1手动注入 2.2自动注入2.2.1XML的autowire自动注入2.2.2@Autowired注解的自动注入3.寻找注入点3.1static的字段或方法为什么不支持3.2桥接方法4.注入点进行注入4.1字段注入4.2Set......