Spring循环依赖详解(看这篇就够了)

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

循环依赖

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

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

比如:A依赖于B、B依赖于A,如下图所示:

图片图片

体现到代码中为:

@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

图片图片

第二步:属性注入B

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

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

图片图片

第三步:属性注入A

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

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

图片图片

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

第四步:初始化B

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

图片图片

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

图片图片

然后整个流程: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都是从这里获取的。

责任编辑:武晓燕 来源: mikechen的互联网架构
相关推荐

2021-12-13 10:43:45

HashMapJava集合容器

2019-08-16 09:41:56

UDP协议TCP

2021-09-30 07:59:06

zookeeper一致性算法CAP

2023-11-03 08:53:15

StrconvGolang

2021-05-07 07:52:51

Java并发编程

2022-03-29 08:23:56

项目数据SIEM

2022-10-17 09:01:09

JavaScripNode.js

2021-07-12 12:20:08

Spring初始化方案

2017-03-30 22:41:55

虚拟化操作系统软件

2023-09-25 08:32:03

Redis数据结构

2023-10-04 00:32:01

数据结构Redis

2023-11-07 07:46:02

GatewayKubernetes

2021-09-10 13:06:45

HDFS底层Hadoop

2021-07-28 13:29:57

大数据PandasCSV

2018-09-26 11:02:46

微服务架构组件

2021-10-21 06:52:17

ZooKeeper分布式配置

2023-12-07 09:07:58

2021-04-11 08:30:40

VRAR虚拟现实技术

2022-08-18 20:45:30

HTTP协议数据

2021-11-10 07:47:48

Traefik边缘网关
点赞
收藏

51CTO技术栈公众号