Spring Bean 循环依赖

在Spring框架中,Bean的创建和管理是其核心功能之一。然而,在复杂的应用系统中,Bean之间可能会形成循环依赖(Circular Dependency),这种情况如果不加以妥善处理,将会导致Spring容器在初始化时抛出异常。本文将深入探讨Spring Bean循环依赖的概念、Spring的解决机制以及我们如何在开发中避免或处理循环依赖。

什么是循环依赖?

循环依赖指的是两个或多个Bean之间通过构造函数、Setter方法或字段注入相互依赖,形成一个闭环。例如,Bean A依赖于Bean B,同时Bean B又依赖于Bean A,这就构成了一个典型的循环依赖。

常见的循环依赖场景

  • 构造函数注入:最容易导致循环依赖的注入方式,因为构造函数是在Bean完全初始化之前调用的,如果此时Bean A需要注入Bean B,而Bean B的初始化又需要Bean A,就会陷入死循环。
  • Setter方法注入:相对构造函数注入而言,Setter方法注入可以通过延迟注入的方式解决循环依赖问题。
  • 字段注入:字段注入的处理方式与Setter方法类似,但通常不推荐使用,因为它破坏了依赖的明确性和可读性。

Spring如何解决循环依赖?

三级缓存

Spring容器通过三级缓存机制解决了基于Setter方法的单例Bean的循环依赖问题。这三级缓存分别是:

  1. 一级缓存(SingletonObjects):存储完全初始化好的Bean,即所有依赖注入都完成的Bean。
  2. 二级缓存(EarlySingletonObjects):存储早期暴露的Bean对象,这些对象已经完成了实例化,但尚未进行属性填充(即依赖注入未完成)。
  3. 三级缓存(SingletonFactories):存储的是ObjectFactory,用于生成Bean的早期引用,以便在需要时能够获取到Bean的早期实例(尚未填充依赖)。

当Spring容器检测到循环依赖时,它会利用三级缓存来提前暴露Bean的早期引用,从而解决依赖注入问题。

流程简述

  1. 当Spring容器需要创建Bean A时,会先检查一级缓存中是否已存在Bean A的实例,如果不存在,则继续。
  2. 接着,Spring会尝试创建Bean A的实例,并将其ObjectFactory加入到三级缓存中。
  3. 随后,Spring在填充Bean A的依赖时,如果发现依赖的Bean B尚未创建,则开始创建Bean B。
  4. 如果Bean B也依赖于Bean A(即出现循环依赖),此时Spring会从三级缓存中获取Bean A的ObjectFactory,调用其getObject方法获取Bean A的早期引用,并将其注入到Bean B中。
  5. 接着,Spring完成Bean B的剩余初始化过程,并将其加入到二级缓存中。
  6. 当Bean B的初始化完成后,Spring回到Bean A的初始化流程,从二级缓存中获取Bean B的实例,完成Bean A的依赖注入和剩余初始化工作。
  7. 最后,将Bean A的实例加入到一级缓存中,供后续使用。
相关推荐
laocooon5238578861 分钟前
C语言枚举知识详解与示例
java·c语言·数据库
月明长歌6 分钟前
【码道初阶】【LeetCode 160】相交链表:让跑者“起跑线对齐”的智慧
java·算法·leetcode·链表
菜鸟小芯9 分钟前
OpenHarmony环境搭建——02-JDK17安装教程
java
原来是好奇心23 分钟前
深入Spring Boot源码(二):启动过程深度剖析
java·源码·springboot
听风吟丶24 分钟前
Spring Boot 自动配置原理深度解析与实战
java·spring boot·后端
原来是好奇心25 分钟前
深入Spring Boot源码(一):环境搭建与初探项目架构
java·gradle·源码·springboot
韩凡25 分钟前
JAVA微服务与分布式(概念版)
java·分布式·微服务
bing.shao26 分钟前
Golang 之闭包
java·算法·golang
济南壹软网络科技有限公司29 分钟前
下一代盲盒系统核心架构解析:JAVA-S1如何打造极致公平与全球化体验
java·开源·盲盒源码·盲盒h5·国际盲盒源码