Spring-bean的循环依赖

本文详细解释了Spring框架中循环依赖的类型,包括构造器和setter/属性循环,以及混合依赖的情况。特别强调了Spring的三级缓存如何处理循环依赖,确保单例bean的正确初始化。
摘要由CSDN通过智能技术生成

版本 Spring Framework 6.0.9​

Spring的循环依赖是指在Spring管理的Bean之间存在互相引用的情况,即两个或多个Bean相互依赖,形成闭环,陷入无限递归或无法完成初始化的状态。

1. 循环依赖的类型

构造器循环依赖

构造器循环依赖,如Bean A通过构造器注入Bean B,Bean B 也通过构造器注入Bean B,由于构造器所需参数必须先实例化,导致Bean A和Bean B都无法获取对方的实例,无法完成初始化。

Spring会抛出BeanCurrentlyInCreationException异常。

在这里插入图片描述

Setter/属性循环依赖(包括方法注入)

Setter/属性循环依赖(包括方法注入),如Bean A通过setter方法注入Bean B ,Bean B 也通过setter方法注入Bean A ,bean A 实例化后,属性填充时发现依赖了bean B,转而实例化bean B再通过setter方法赋值,而Bean B属性填充时已经可以拿到实例并初始化完成的Bean A。

Spring容器通过三级缓存(单例对象提前曝光机制)可以解决部分的setter/属性循环依赖问题。

在这里插入图片描述

混合型循环依赖

如果循环依赖涉及构造器注入和setter/属性注入的混合。

例子1:如Bean A(OrderService)通过setter方法注入Bean B (UserService),Bean B 通过构造器注入Bean A

  • bean A 通过无参构造实例化后,属性填充时发现依赖了Bean B,转而实例化bean B,
  • 当Bean B通过有参构造创建对象时,可以从缓存中拿到bean A,从而完成实例化、初始化。
  • bean B完成实例化后,bean A也可从缓存中获取B的实例,完成初始化。
    在这里插入图片描述

例子2:如Bean A(OrderService)通过构造器注入Bean B (UserService),Bean B 通过setter方法注入Bean A

  • bean A 通过有参构造器实例化时发现依赖了Bean B,Bean B还未创建,转而实例化bean B,
  • bean B 通过无参构造器实例化后,属性填充时发现依赖了Bean A。转而实例化Bean A。
  • 因为bean B已经实例化,所以 bean A 可以拿到bean B 通过有参构造器实例化。
  • bean B 等 bean A实例化完后再进行属性填充。

在这里插入图片描述

虽然例子2也可以推导,但Spring会抛出BeanCurrentlyInCreationException异常。
在这里插入图片描述

下面是spring 创建bean的简化过程,

  • 例子2中bean A构造器实例化发现依赖了bean B,进入bean B的创建流程,bean B到属性填充阶段时,发现依赖了beanA,再次进入bean A的创建流程,此时bean A已标记为创建中,但又无法从三级缓存中获取,抛出BeanCurrentlyInCreationException异常。
  • 而在例子1中bean A先通过无参构造实例化,放入了三级缓存,bean A通过构造器实例化发现依赖了bean A,再次进入bean A的创建流程,此时bean A可从三级缓存中获取。

在这里插入图片描述

2. 三级缓存

一级缓存(singletonObjects)

存放已经完全初始化好的单例 bean。

二级缓存(earlySingletonObjects)

存放原始对象(即仅通过无参构造器创建的对象,尚未填充属性)。

三级缓存(singletonFactories)

存放 bean 工厂对象(可立即创建原始对象的工厂)。

在这里插入图片描述

三级缓存机制处理单例 bean 的循环依赖

由于bean通过无参构造创建对象会放入三级缓存,在遇到循环依赖时,Spring 先尝试从缓存中获取已经创建的部分初始化对象(二级缓存),如果没有则通过工厂对象(三级缓存)创建“半成品”对象并放入二级缓存,使得依赖链中的其他 bean 能够继续进行初始化。这一过程确保了在循环依赖场景下,Spring 能够按需暴露 bean 的早期版本,从而顺利解除循环,完成 bean 的实例化。
在这里插入图片描述

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值