Spring 如何解决循环依赖,网上的资料很多,但是感觉写得好的极少,特别是源码解读方面,我就自己单独出一篇,这篇文章绝对肝!
不 BB,上文章目录 。
文章插图
图片
1. 基础知识1.1 什么是循环依赖 ?一个或多个对象之间存在直接或间接的依赖关系,这种依赖关系构成一个环形调用,有下面 3 种方式 。
文章插图
图片
我们看一个简单的 Demo,对标“情况 2” 。
@Servicepublic class LouzAI1 {@Autowiredprivate Louzai2 louzai2;public void test1() {}}@Servicepublic class Louzai2 {@Autowiredprivate Louzai1 louzai1;public void test2() {}}
这是一个经典的循环依赖,它能正常运行,后面我们会通过源码的角度,解读整体的执行流程 。1.2 三级缓存解读源码流程之前,spring 内部的三级缓存逻辑必须了解,要不然后面看代码会蒙圈 。
- 第一级缓存:singletonObjects , 用于保存实例化、注入、初始化完成的 bean 实例;
- 第二级缓存:earlySingletonObjects,用于保存实例化完成的 bean 实例;
- 第三级缓存:singletonFactories,用于保存 bean 创建工厂,以便后面有机会创建代理对象 。
文章插图
图片
执行逻辑:
- 先从“第一级缓存”找对象 , 有就返回,没有就找“二级缓存”;
- 找“二级缓存”,有就返回,没有就找“三级缓存”;
- 找“三级缓存”,找到了,就获取对象,放到“二级缓存”,从“三级缓存”移除 。
文章插图
图片
整个执行逻辑如下:
- 在第一层中,先去获取 A 的 Bean,发现没有就准备去创建一个,然后将 A 的代理工厂放入“三级缓存”(这个 A 其实是一个半成品,还没有对里面的属性进行注入),但是 A 依赖 B 的创建,就必须先去创建 B;
- 在第二层中,准备创建 B,发现 B 又依赖 A,需要先去创建 A;
- 在第三层中,去创建 A,因为第一层已经创建了 A 的代理工厂,直接从“三级缓存”中拿到 A 的代理工厂,获取 A 的代理对象,放入“二级缓存”,并清除“三级缓存”;
- 回到第二层,现在有了 A 的代理对象,对 A 的依赖完美解决(这里的 A 仍然是个半成品),B 初始化成功;
- 回到第一层,现在 B 初始化成功,完成 A 对象的属性注入,然后再填充 A 的其它属性,以及 A 的其它步骤(包括 AOP),完成对 A 完整的初始化功能(这里的 A 才是完整的 Bean) 。
- 将 A 放入“一级缓存” 。
2. 源码解读注意:Spring 的版本是 5.2.15.RELEASE,否则和我的代码不一样?。。?
上面的知识,网上其实都有,下面才是我们的重头戏,让你跟着楼仔,走一遍代码流程 。
2.1 代码入口
文章插图
图片
文章插图
图片
这里需要多跑几次,把前面的 beanName 跳过去,只看 louzai1 。
文章插图
图片
文章插图
图片
2.2 第一层
文章插图
图片
进入 doGetBean() , 从 getSingleton() 没有找到对象 , 进入创建 Bean 的逻辑 。
文章插图
图片
推荐阅读
- API接口脱敏:如何安全地处理敏感数据?
- 详细解析BIOS如何清除硬盘数据
- 如何有效设置和管理电脑用户账户及权限
- 如何快速提升电脑启动速度?这几种方法简单又实用!
- 如何为父母办理异地就医备案?常见问题解答来了
- 火龙果该如何保存 火龙果怎么保鲜
- 鱼缸水浑浊原因和解决方案 底滤鱼缸水浑浊原因和解决方案
- 虎年属猪人的运势如何 虎年属猪人的运势如何呢
- 42岁香港女星自曝:因私生活不协调离婚,解决不了生儿育女的问题
- 电商的运营模式是什么 电商运营模式如何运作的