Spring 循环依赖问题
解决循环依赖的前置条件
- 出现循环依赖的 Bean 必须是单例的
- 依赖注入的方式不能都是构造注入的方式
整体过程
Spring 通过三级缓存解决了循环依赖问题, 一级缓存为单例池, 二级缓存为早期暴光对象, 也就是还没有属性注入及初始化的对象, 三级缓存为早期暴露的单例工厂, 二级缓存中存储的就是从这个工厂获取的对象
- 调用 doGetBean() 方法, 想要获取 beanA, 于是调用 getSingleton() 方法从缓存中查找 beanA
- 在 getSingleton() 方法中, 从一级缓存中查找, 没有并返回null
- doGetBean() 方法中获取的 beanA 为 null, 于是走到对应的处理逻辑, 调用 getSingleton() 参数为 ObjectFactory 的重载方法
- 在 getSingleton() 方法中, 先将 beanA_name 添加到一个集合中, 用于标记该 bean 正在创建, 然后回调匿名内部类的 createBean() 方法
- 进入 doCreateBean() 方法, 先反射调用构造器创建出 beanA 的实例, 然后判断是否为单例, 是否允许提前暴露引用, 单例一般为 true, 是否正在创建中, 判断为 true 则将 beanA 添加到三级缓存中
- 对 beanA 进行属性填充, 此时检测到 beanA 依赖于 beanB, 于是开始查找 beanB
- 调用 doGetBean() 方法, 与上面的 beanA 过程一样, 到缓存中查找 beanB, 没有则创建, 然后进行属性填充
- 此时 beanB 依赖于 beanA, 调用 getSingleton() 获取到 beanA, 依次从一级, 二级, 三级缓存中查找, 此时从三级缓存中获取到 beanA 的创建工厂, 通过创建工厂获取到 singletonObject 指向的就是 doCreateBean() 方法中实例化的 beanA
- 这样 beanB 就获取到 beanA 的依赖, 于是beanB 顺利的完成实例化, 并将 beanA 从三级缓存中移动到二级缓存中
- 随后 beanA 继续他的属性填充工作, 也能获取到 beanB, 此时可以完成创建, 回到 getSingleton() 方法中继续向下执行, 将 beanA 从二级缓存移动到一级缓存中
整体过程图示
没有 AOP
有 AOP
二级缓存能解决循环依赖问题吗
使用二级缓存解决循环依赖, 意味着所有的 Bean 在实例化后就要完成 AOP 代理, 违背了 Spring 的设计原则, 设计之初就是通过后置处理器来在 bean 的生命周期的最后一步来完成 AOP 代理, 而不是在实例化后就进行 AOP 代理