源码级详解Spring的三级缓存,循环依赖的处理流程

一.什么是三级缓存

1.一级缓存:存放已经初始化完成的Bean

2.二级缓存:存放半成品Bean,既实例化完成未初始化的Bean。

3.三级缓存:存放bean工厂

二.为什么是三级缓存

一级缓存是必须的,这个我们没有什么疑问。那为什么要有二级缓存,二级缓存主要是用来解决循环依赖的问题。

2.1什么是循环依赖

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

举个简单的例子:

kotlin
复制代码@Service
public class AService {@Resourceprivate BService bService;
}
kotlin
复制代码@Service
public class BService {@Resourceprivate AService aService;
}

AService中依赖了BService,而BService又依赖了AService,这样就构成循环依赖。

Spring是允许单例bean进行循环依赖的。

2.2循环依赖的bean注入流程

下面我就带大家从源码的层面,讲解三级缓存是如何解决循环依赖问题的。

1.doCreateBean方法会调用createBeanInstance方法来对beanA进行实例化。

2.addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));会将生成代理对象的工厂放入到三级缓存。

3.beanA调用populateBean方法,注入beanB实例。

在注入beanB实例的过程中,发现beanB依赖了beanA,需要将beanA加载出来。

会再次对beanA调用doGetBean方法。这时候,getSingleton方法就真正派上用场了。

4.在getSingleton方法中,会将beanA的bean工厂从三级缓存中取出来,调用getObject方法,也就是getEarlyBeanReference方法,将返回结果放入二级缓存,同时从三级缓存移除掉。

5.把不完整的beanA注入到beanB中

6.beanB执行addSingleton(beanName, singletonObject)方法,这个方法将beanB放入到一级缓存,且从二级缓存中移除掉。

7.beanA注入beanB实例。

8.beanA完成属性填充和初始化,执行addSingleton(beanName, singletonObject)方法,将BeanA放入到一级缓存。

从上面注入的流程,可以看出,如果没有存放半成品的二级缓存,那么循环依赖是无法解决的。如果我们在实例化完beanA,立刻创建出代理对象放到二级缓存,再填充beanA的属性以及初始化,这样也可以正常完成BeanA,BeanB的注入。这样就省掉了第三级缓存。那第三级缓存存在的原因是什么呢?

2.3.第三级缓存在的原因

要理清楚,三级缓存存在的原因主要原因有两个,一是因为AOP,二是循环依赖。如果没有Spring AOP和循环依赖,那么就不需要使用三级缓存。

我们先看下,不存在循环依赖的代理对象是如何生成的?

上图第五步的时候,会调用AbstractAutoProxyCreator类的
postProcessAfterInitialization方法,创建代理对象。对于不涉及到循环依赖的bean,会在初始化之后,创建代理对象。

而对于涉及到循环依赖的bean,如果没有三级缓存,在对象实例化后,就要立刻生成其代理对象,这样会影响到bean注入整个代码的逻辑。增加三级缓存,一可以防止循环依赖的对象多次被代理还可以做到循环引用的bean,在被循环引用时,代理对象被创建且注入进去,不涉及到循环引用的bean,等到初始化之后创建代理对象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/268117.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Flutter的BuildContext简介

文章目录 BuildContext 简介BuildContext的主要作用 BuildContext 简介 BuildContext是Flutter中的一个重要概念,表示当前Widget在树中的位置上下文。它是一个对Widget树的一个位置的引用,用于查找、访问和操作该位置上的相关信息。每个Widget都有一个关…

MSSQL存储过程的功能和用法:解密数据库编程的神秘面纱

🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…

充分发挥SQL能力之数列

SQL数列 1、数列概述2、SQL数列2.1、简单递增序列2.2、等差数列2.3、等比数列3、SQL数列的应用3.1、连续问题3.2、多维分析1、数列概述 数列是最常见的数据形式之一,实际数据开发场景中遇到的基本都是有限数列。常见的数列例如:简单递增序列、等差数列、等比数列等 如何充分…

图形化编程:开启儿童创新思维的新篇章

随着科技的飞速发展,少儿编程已经成为了当今社会的一项重要技能。越来越多的家长和教育者开始关注如何让孩子从小接触编程,培养他们的创新思维和解决问题的能力。6547网认为图形化编程作为一种简单易学、趣味性强的编程方式,正逐渐成为儿童编…

十年前端之离别的旋律

在一家名叫“梦想家”的小公司里,有一个普通的程序员,他的名字叫做小帅。每天默默地坐在角落里,默默地写着代码,默默地为公司付出。他的眼睛里总是充满了对工作的热爱和对生活的热情,但他的内心却隐藏着一个秘密&#…

立体声数模转换芯片GC4344的性能有哪些?为什么是DVD 播放解码器、数字通信设备等音频设备的理想选择

GC4344 是一款立体声数模转换芯片,内含插值滤波器、multi-bit 数模转换器、输出模 拟滤波器。GC4344 支持大部分的音频数据格式。GC4344 基于一个带线性模拟低通滤波器的四 阶 multi-bitΔΣ调制器,而且本芯片可以通过检测信号频率和主时钟频率&#xff…

Python网络爬虫的基础理解-对应的自我理解误区

##通过一个中国大学大学排名爬虫的示例进行基础性理解 以软科中国最好大学排名为分析对象,基于requests库和bs4库编写爬虫程序,对2015年至2019年间的中国大学排名数据进行爬取:(1)按照排名先后顺序输出不同年份的前10…

网易有道强力开源中英双语语音克隆

项目地址(基于PromptTTS): https://github.com/netease-youdao/EmotiVoice EmotiVoice Docker镜像 尝试EmotiVoice最简单的方法是运行docker镜像。你需要一台带有NVidia GPU的机器。先按照Linux和Windows WSL2平台的说明安装NVidia容器工具…

【Deeplearning4j】小小的了解下深度学习

文章目录 1. 起因2. Deeplearning4j是什么3. 相关基本概念4. Maven依赖5. 跑起来了,小例子!6. 鸢尾花分类代码 7. 波士顿房价 回归预测代码 8. 参考资料 1. 起因 其实一直对这些什么深度学习,神经网络很感兴趣,之前也尝试过可能因…

隐语开源|周爱辉:隐语 TEE 技术解读与跨域管控实践

“隐语”是开源的可信隐私计算框架,内置 MPC、TEE、同态等多种密态计算虚拟设备供灵活选择,提供丰富的联邦学习算法和差分隐私机制 开源项目 github.com/secretflow gitee.com/secretflow 11月25日,「隐语开源社区 Meetup西安站」顺利举办&…

性能测试:方法、工具与最佳实践

目录 前言 1. 为什么进行性能测试? 2. 性能测试方法 3. 性能测试工具 Apache JMeter: LoadRunner: Gatling: Apache ab (Apache Benchmark): Locust: Tsung: BlazeMeter: K6: Neoload: WebLOAD: 4. 最佳实践 设定明确的性能测试目标: 模…

资深测试总结,性能测试目的如何做?主要看什么指标?

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 1、性能测试是什么…