最通俗的方式理解Spring循环依赖三级缓存

开发 架构
我想今天,用最通俗易懂的方式给大家重新梳理一下Spring循环依赖的三级缓存,保证让你听懂了。

今天,有位粉丝找我,说要耽误我5分钟时间,想让我帮助它理解一下Spring循环依赖的三级缓存,绕晕了一个星期,没有想明白。我想今天,用最通俗易懂的方式给大家重新梳理一下,保证让你听懂了。

1、什么是循环依赖?

循环依赖就是指循环引用,是两个或多个Bean相互之间的持有对方的引用。循环依赖有三种形态:

(1)相互依赖,也就是A 依赖 B,B 又依赖 A,它们之间形成了循环依赖。

(2)三者间依赖,也就是A 依赖 B,B 依赖 C,C 又依赖 A,形成了循环依赖。

(3)自我依赖,也是A依赖A形成了循环依赖自己依赖自己。

2、如何解决循环依赖问题?

循环依赖本身没有问题,问题是Spring中加入了依赖注入机制,也就是自动给属性赋值。当创建Bean实例化以后,需要给Bean中需要赋值的属性全部自动赋值才能交给用户使用。但如果是循环依赖的情况,以两个Bean相互依赖的情况为例,

假设Bean A已经实例化,但是Bean A中需要自动赋值Bean B并没有初始化,但如果Spring立刻去初始化Bean B,发现Bean B中需要自动赋值的Bean A没有初始化,如果这样相互等待,就会形成死循环,最终,有可能导致Spring容器都无法启动。

就好比,我们以前读书的时候,老师经常教我们一个考试方法,就是遇到难题不会答的时候,不要死磕,要继续往下做其他的题。否则,会因为一道难题卡住影响到整个的答题进度,还会影响正常的发挥,影响考试结果。

那这个问题该怎么解决呢?使用缓存。

就是将所有实例化好的Bean,全部放到一个容器中缓存起来,并且将已经完成实例化但没有完成赋值的,打上标记。

然后,等Bean全部实例化以后,再重新扫描一遍容器,将没有完成赋值的Bean属性完成赋值,这个时候,所有未完成赋值的Bean都已经能够找到对应的实例了。

那么问题来了。解决循环依赖问题,一定要二级缓存吗?答案是不一定。但是Spring中为什么又要设计二级缓存呢?

这时候,我们可以这样理解,假设,我们只有一个缓存容器,并且缓存是直接开放给用户可以调用的,如果将未完成赋值的Bean和已完成赋值的Bean全部放到同一个容器,那这个时候,调用者就有可能拿到未赋值的Bean,这样的Bean对于用户来说是不可用的,可能会导致空指针异常。

所以,Spring设计者,才有了这样一个设计,将能够直接提供给用户使用的Bean放到一级缓存中,这样Bean称之为终态Bean,或者叫成熟Bean。

将已经完成初始化,但还不能提供给用户使用的Bean单独放到一个缓存容器中,就是二级缓存,这样的Bean称之为临时Bean,或者叫早期Bean。

依照以上的分析,理论上二级缓存就能解决循环依赖问题,那为什么Spring还要设计一个三级缓存呢?

3、如何理解三级缓存?

我们都知道,Spring中有很多注入的Bean是需要创建代理Bean的,但是,不是所有的Bean都需要再实例化之后立马就会创建代理Bean。是要等到Bean初始化全部完成之后才创建代理Bean。因此,循环依赖的出现,Spring又不得不去提前创建代理Bean。如果不创建代理Bean,注入原始Bean就会产生错误。因 此,Spring设计三级缓存,专门用来存放代理Bean。但是,创建代理Bean的又不同的规则,因此,Spring三级缓存中,并不是直接保存代理Bean的引用,而是保存创建代理Bean的Factory。

4、总结

所以,总结结论为,单纯解决循环依赖可以只用二级缓存,但是如果涉及到代理对象的循环依赖,就需要用到三级缓存。其实一、二、三级缓存是根据获取对象的顺序来命名的,我们完全可以这样理解,一级缓存就是终态缓存,二级缓存是临时缓存、三级缓存是代理工厂的缓存。

这张图完整地描述了一、二、三级缓存的运行逻辑。

责任编辑:姜华 来源: Tom弹架构
相关推荐

2023-12-12 17:44:13

三级缓存Bean

2024-03-04 08:47:17

Spring框架AOP

2022-03-01 18:03:06

Spring缓存循环依赖

2022-12-02 12:01:30

Spring缓存生命周期

2023-02-26 11:15:42

缓存循环依赖

2021-01-29 14:14:47

动态代理缓存

2024-04-15 08:17:21

Spring依赖注入循环依赖

2020-02-10 15:50:18

Spring循环依赖Java

2024-03-18 00:00:00

SpringBean设计

2024-04-12 07:51:05

SpringBean初始化

2020-02-06 13:40:35

编程缓存优化

2022-01-12 07:48:19

缓存Spring 循环

2022-08-07 23:52:10

Python模块数据分析

2021-06-27 21:06:47

开发循环依赖

2023-05-04 08:06:27

Spring循环依赖

2010-11-10 09:13:37

综合布线综合布线改造

2009-09-24 11:16:22

CCNA和CCNP

2011-08-01 10:35:26

数据库外模式模式

2020-11-27 06:28:55

Spring循环依赖

2019-11-26 14:30:20

Spring循环依赖Java
点赞
收藏

51CTO技术栈公众号