Spring源码-循环依赖

循环依赖问题

先分析下bean生命周期, 简化版:

1. 扫描, 获取所有的BeanDefinition,存入BeanDefinitionMap

2. 遍历BeanDefinition, 准备创建bean

3. 推断构造方法, 通过反射, 实例化bean对象(原始对象)

4. 属性赋值

5. 初始化前, 初始化

6. 初始化后, 可能AOP

7. 把经过完整生命周期对象放入单例池SingletonObjects

触发循环依赖-场景1:

ABean创建 > A依赖了B > 创建BBean > B依赖了A > 发现ABean正在创建

循环依赖解决思路

加二级缓存, 在bean实例化后, 属性赋值前, 将原始bean(未完成完整生命周期)存入缓存, B依赖A时, 先去缓存拿, 这样A和B都能正常创建.

Spring源码-循环依赖_第1张图片

只加二级缓存, 似乎能解决依赖问题. 但是, 如果考虑A要AOP的话, B赋值的A对象是原始bean, 而ABean是初始化后生成的代理对象, 两者不一致, 不能彻底解决问题.

此时可以考虑在初始化后, 将AOP创建代理对象过程提前, 并将AOP代理对象放入缓存, 这里就需要用三级缓存singletonFactories, key是beanName, value是ObjectFactory, ObjectFactory是一个函数式接口,Lambda表达式:() -> getEarlyBeanReference(beanName, mbd, bean).

三级缓存

  1. singletonObjects:单例池, 缓存的是经过完整生命周期的bean
  2. earlySingletonObjects:缓存的是未经过完整生命周期的bean. 如果出现了循环依赖, 会提前把未经过完整生命周期的bean放入二级缓存, 如果这个bean有AOP, 放入的是代理对象, 否则放原始对象,都是未经过完整生命周期的bean
  3. singletonFactories:存的是一个ObjectFactory, 一个lambda表达式.当bean实例化后, 会生成一个lambda表达式,放入三级缓存. 这个lambda可能被执行, 也可能不被执行. 当执行时候, 可以获取原始对象或者代理对象.在bean属性赋值时, 如果发现循环依赖(当前正在创建的bean被属性bean依赖),才会执行lambda表达式拿到一个对象, 放入二级缓存.如果bean需要AOP, lambda表达式返回的是代理对象, 否则返回原始对象.

你可能感兴趣的:(spring,java)