Spring解决循环依赖

循环依赖解决

singletonObjects: 用于存放完全初始化好的 bean,从该缓存中取出的 bean 可以直接使用

earlySingletonObjects: 存放早期曝光的 bean 对象(尚未填充属性),用于解决循环依赖

singletonFactories: 存放 bean 工厂对象,用于解决循环依赖

  1. setter循环依赖
    假设对象 a 通过 setter 方法持有 b,b 又持有a
    创建 a 时,正常创建,需要注入属性 b,则去创建对象 b.
    创建 b 时,发现 b 依赖于 a,则去获取 a.此时发现 a 在 singletonsCurrentlyInCreation 这个 map 中,表示 a 正在创建.

在容器再次发现 beanB 依赖于 beanA 时,容器会获取 beanA 对象的一个早期的引用(early reference),并把这个早期引用注入到 beanB 中,让 beanB 先完成实例化.beanB 完成实例化,beanA 就可以获取到 beanB 的引用,beanA 随之完成实例化

创建 a 对象时
1.尝试从 singletonObject 缓存中获取 bean,获取不到 并且 且 当前 bean 没有处于正在创建中,返回 null.
2.singleton bean a 的创建
2.1.先尝试从 singletonObjects 中获取
2.2.若上面获取不到
2.2.1.向 singletonsCurrentlyInCreation 缓存中记录 beanName,表示 a 正在创建中
2.2.2.使用传入的 singletonFactory 创建 bean
2.2.2.1.createBean() 中 根据不同的实例化策略实例化 bean,如 工厂方法 或 构造器.实例化后包装成 BeanWrapper.
2.2.3.判断是否需要提早暴露: 单例 且 允许循环依赖 且 当前bean正在创建中,则需要提前暴露,用于解决循环依赖
2.2.3.1.若需要早期曝光.则将 singletonFactory 添加到 singletonFactories 中,并从 earlySingletonObjects 中移除缓存.这里传入的 singletonFactory 的 getObject() 方法 返回的是 getEarlyBeanReference,即早期引用的 bean.
2.2.4.populateBean() 对 bean 进行属性装配.其中可能存在依赖于其他 bean 的属性,则会递归初始化.

创建 b 对象时,流程和上面类似.

当 b 调用 populateBean() 装配依赖的 a 时,流程如下:
1.从 beanFactory 中获取 a
1.1.尝试从 singletonObject 缓存中获取 bean
1.2.由于上面获取不到,且 a 当前正在创建中,则尝试从 earlySingletonObjects(早期曝光)缓存中获取 a
1.3.由于 earlySingletonObjects 中也获取不到a,且允许早期曝光(earlyReference),则从 singletonFactories 中获取 singletonFactory
1.4.通过 singletonFactory.getObject() 返回早期曝光的 bean,这个 bean a 还未完成 populateBean() 属性装配
1.5.创建完早期曝光 bean 后,添加到 earlySingletonObjects 缓存中,下次直接从这个缓存中取 早期曝光的 bean 了.并且从 singletonFactories 移除掉,因为没必要再通过它来创建早期曝光的 bean 了.

装配完了,后面调 init-method, InitializingBean, BeanPostProcessor 等
  1. 构造器循环依赖
    由于指定了带参的构造函数,所以使用 autowireConstructor()来创建bean.
    return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);

getSingleton()时,singletonFactories 中没有 ObjectFactory.则会调 getSingleton() 创建单例 bean,由于在 singletonsCurrentlyInCreation 里有当前正在创建的 bean 记录,所以抛 BeanCurrentlyInCreationException 异常.

为什么没添加 ObjectFactory 到 singletonFactories 中,因为构造器方式 缺少

根据:单例 且 允许循环依赖 且 当前bean正在创建中,检测循环依赖,判断是否需要 提早暴露这段逻辑

你可能感兴趣的:(Spring)