news 2026/10/31 19:58:42

【Spring Boot】Spring Boot解决循环依赖

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Spring Boot】Spring Boot解决循环依赖
目录
  • 循环依赖
    • 一、前言
    • 二、Bean的创建过程
    • 三、 循环依赖检测机制
      • 3.1 实例化阶段
      • 3.2 属性填充阶段
      • 3.3 依赖注入

循环依赖

一、前言

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

Spring是如何发现这种循环依赖的问题的呢?
通过依赖图来检测和发现循环依赖问题。如下步骤:

二、Bean的创建过程

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

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

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

三、 循环依赖检测机制

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

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

具体的检测步骤

3.1 实例化阶段

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

3.2 属性填充阶段

在属性填充阶段,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"); } }
3.3 依赖注入

Spring的依赖注入过程:

  1. 实例化Bean A

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

  1. 填充Bean A的属性

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

  1. 填充Bean B的属性

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

  1. 完成Bean B的创建

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

  1. 回到Bean A的创建

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/31 1:37:38

软件测试基础:从分类到流程的全方位指南

作为一名正在学习软件测试的初学者,我发现将笔记整理成博客文章不仅能帮助自己巩固知识,还能与他人分享经验。今天,我想分享一些测试的基础概念,包括常见的测试分类、软件质量模型以及测试流程。这些内容基于我的学习笔记&#xf…

作者头像 李华
网站建设 2026/10/23 15:11:11

Postman接口测试与自动化实战

Postman在接口测试与自动化测试中的全面应用指南 Postman作为业界领先的API开发与测试工具,在接口测试和自动化测试领域发挥着核心作用。下面通过具体的技术实现和实际案例,系统阐述其应用方案。 一、接口测试核心能力与应用场景 1. 基础请求构建与调…

作者头像 李华
网站建设 2026/10/17 19:46:47

QT聊天项目(11)

简介我们把注册界面再优化完善一下一、增加定时按钮点击获取验证码后需要让按钮显示倒计时&#xff0c;然后倒计时结束后再次可点击。 添加TimberBtn类#ifndef TIMERBTN_H #define TIMERBTN_H #include <QPushButton> #include <QTimer> class TimerBtn : public Q…

作者头像 李华
网站建设 2026/10/17 23:35:32

自己在Simulink上搭建的四永磁同步电机偏差耦合转速同步控制仿真模型

自己在simulink上搭建的四永磁同步电机偏差耦合转速同步控制仿真模型。最近在实验室折腾多电机同步控制&#xff0c;发现四台永磁同步电机要玩转转速同步真是挺有意思的挑战。特别是当负载突变时&#xff0c;各电机转速就像脱缰野马互相拉扯。搞了个基于偏差耦合的控制方案&…

作者头像 李华