【重难点】【Spring 03】循环依赖
一、循环依赖
1.定义
循环依赖的定义很简单,就是 ServiceA 中注入了 ServiceB,ServiceB 中也注入了 ServiceA,Spring 通过三级缓存解决循环依赖的问题
2.Bean 的生命周期
- Spring 扫描有注解的 class 得到 BeanDefinition
- 根据 BeanDefinition 生成 Bean(根据 class 推断构造方法,使用反射构造原始对象)
- 将创建原始对象的 lambda 表达式放入三级缓存中
- 对原始对象进行依赖注入
- 如果原始对象中的方法需要 AOP,那么还需要生成代理对象放入二级缓存中
- 最后把最终生成的对象或者代理对象放入一级缓存中,使用的时候直接从一级缓存中获取
3.三级缓存
- 一级缓存:singletonObjects
- 二级缓存:earlySingletonObjects
- 三级缓存:singletonFactories
三种缓存各自的作用
- singletonObjects:存放的是已经经历了完整生命周期的 Bean 对象
- earlySingletonObjects:存放的是原始 Bean 对象,即未经历完整生命周期的 Bean 对象
- singletonFactories:存放的是创建原始 Bean 对象的 lambda 表达式,也被称为对象工厂
4.解决流程
创建 ServiceA 的第一阶段
- 将创建 ServiceA 的 lambda 表达式放到三级缓存中
- 在 ServiceA 的原始对象中注入 ServiceB
- 我们先尝试在一级缓存中获取 ServiceB,发现一级缓存中没有 ServiceB
- 接着去二级缓存中找,发现二级缓存中也没有
- 最后我们在三级缓存中也没有找到,这个时候我们就需要创建 ServiceB
创建 ServiceB
- 将创建 ServiceB 的 lambda 表达式放到三级缓存中
- 在 ServiceB 的原始对象中注入 ServiceA
- 我们先尝试在一级缓存中获取 ServiceA,发现一级缓存中没有
- 接着去二级缓存中找,发现二级缓存中也没有
- 最后我们在三级缓存中找到了,执行 lambda 表达式得到 ServiceA
- 然后将 ServiceA 放入二级缓存中,并且注入到 ServiceB 中
- 执行三级缓存中的 lambda 表达式,获取 ServiceB
- 将 ServiceB 放入一级缓存中
- ServiceB 创建完成
创建 ServiceA 的第二阶段
- 将创建完成的 ServiceB 注入到 ServiceA 的原始对象中
- 将二级缓存中的 ServiceA 放入一级缓冲中
- ServiceA 创建完成