图解 Spring 循环依赖,一文吃透!

举报
mikechen的互联网架构 发表于 2024/11/18 22:32:10 2024/11/18
【摘要】 Spring 循环依赖如何解决,是大厂面试高频,本文详细解析,建议收藏。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。

关注△mikechen的互联网架构△,10年+BAT架构经验倾囊相授


image.png

大家好,我是 mikechen | 陈睿

Spring 循环依赖如何解决?是大厂面试高频。

本篇,我们重点详解 Spring 循环依赖解决。@mikechen

循环依赖

在探讨Spring循环依赖的解决方式以前,我们先来回忆一下什么是循环依赖。

循环依赖:就是多个bean之间相互依赖,形成了一个闭环。

比如:A依赖于B、B依赖于A。

如下图所示:

image.png

体现到代码中为:

@Component
public class A{
   // 依赖B
   @Autowired
   private B b;
   public B getB() {
      return b;
   }
}

@Component
public class B {
   // 依赖A
   @Autowired
   private A a;
   public A getA() {
      return a;
   }
}

Spring的循环依赖过程:

  • 首先实例化A -> 属性填充注入B -> B还没有实例化;
  • 需要先进行实例化B(A等待) -> 实例化B -> 注入A -> A实例化未完成,无法注入 -> 实例化B失败 -> 实例化A失败。

如此反复,就进入死循环了。

Spring如何解决循环依赖

下面,我还是用 A -> B -> A 的场景,我们按照过程一步步来分析,看一下Spring 是如何解决循环依赖的。

第一步:首先是实例化A

image.png

第二步:属性注入B

执行到属性填充环节需要注入B,因为Spring管理的bean默认是单例的,为防止重复创建Spring会先去容器中查找B,如果查找不到再进行创建。

如果Spring容器中是没有B,需要先实例化B,流程和实例化一致,如下图所示:

image.png

第三步:属性注入A

此时B也执行到属性填充的环节了,此时又需要注入A,此时还是会先去Spring容器中查找A,此时的A虽然没在单例池中,但是因为在创建中并且也在三级缓存中了。

所以此时获取A的流程就发生了变化,不再是直接创建,而是会从三级缓存中获取A,如下图所示:

image.png

三级缓存存放的并不是bean对象,而是生成bean的ObjectFactory,然后放入二级缓存中,同时返回A进行依赖注入。

第四步:初始化B

此时,继续执行B的实例化, 并将B从正在创建列表移出 , 将B放入一级缓存,同时将B在二级缓存和三级缓存中删,最后返回B。

image.png

在B实例化完成并返回后,A的实例化流程也从等待着苏醒继续执行,后续流程和B的完全一致。

image.png

然后整个流程:A -> B -> A的场景就结束了。

这样Spring通过三级缓存来解决循环依赖的,提前暴露的对象存放在三级缓存中,二级缓存存放过渡bean,一级缓存存放最终形态的bean。

Spring三级缓存

// 从上至下 分表代表这“三级缓存”
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); //一级缓存
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); // 二级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 三级缓存

1.三级缓存(singletonFactories)

singletonFactories:单例对象工厂的cache,存放 bean 工厂对象,用于解决循环依赖。

2.二级缓存(earlySingletonObjects)

主要存放过渡bean,也就是三级缓存中ObjectFactory产生的对象。

提前曝光的单例对象的cache,存放原始的 bean 对象:尚未填充属性,用于解决循环依赖。

3.一级缓存(singletonObjects)

也被称为单例池,去存放已经创建完成,并且属性也注入完毕的对象,一般情况我们获取bean都是从这里获取的。

以上,是 Spring 循环依赖的详细解析,欢迎评论区留言交流或拓展。

我是 mikechen | 陈睿 ,关注【mikechen的互联网架构】,10年+BAT架构技术倾囊相授。

新的架构专题内容,第一时间更新至:阿里架构师进阶全部合集

本文已同步我的技术博客 www.mikechen.cc,更新至我原创的《30W+字阿里架构技术合集》中。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。