Spring 解决循环依赖中时间长了容易模糊的点,记录下来方便看

三级缓存位置

public class DefaultSingletonBeanRegistry extends ... {
    /**
     * 一级缓存,缓存生成好的单例对象
     */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    /**
     * 三级缓存,缓存『对已经实例化的Bean提前执行该Bean所有BeanPostProcessor』的延迟处理
     */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
  
    /**
     * 二级缓存,缓存已经实例化并提前执行完该Bean所有BeanPostProcessor的Bean(此时还未填充及初始化)
     */
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
}

Spring 处理 Bean 的主要流程

  1. 实例化 Bean,生成对象;
  2. 填充 Bean,处理 Bean 的属性依赖;
  3. 初始化 Bean,执行初始化方法、 BeanPostProcessor。

Spring 解决循环依赖的关键流程

DefaultSingletonBeanRegistry 类中,解决循环依赖的流程

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   //从单例对象(一级缓存)中获取
   Object singletonObject = this.singletonObjects.get(beanName);
   //不在一级缓存中,并且该Bean正在创建中
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      synchronized (this.singletonObjects) {
         //从提前执行完BeanPostProcessor的Bean的缓存(二级缓存)中获取
         singletonObject = this.earlySingletonObjects.get(beanName);
         //不在二级缓存中
         if (singletonObject == null && allowEarlyReference) {
            //获取该Bean的ObjectFactory(三级缓存),用于提前执行对该Bean的所有BeanPostProcessor
            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            if (singletonFactory != null) {
               //执行所有BeanPostProcessor
               singletonObject = singletonFactory.getObject();
               //加入二级缓存
               this.earlySingletonObjects.put(beanName, singletonObject);
               //移除三级缓存
               this.singletonFactories.remove(beanName);
            }
         }
      }
   }
   return singletonObject;
}

为什么要缓存 ObjectFactory 的延迟处理

结合 Spring 对 Bean 的处理过程,正常情况下 BeanPostProcessor 的执行是在初始化的时候去做,而且并不是所有 Bean 都有 AOP(增强旧对象,返回增强后的新对象)的需求,只有在遇到循环依赖的场景,才需要提前执行 BeanPostProcessor,以便能让其他 Bean 获取到增强后的 Bean。

所以让所有 Bean 都提前执行 BeanPostProcessor 是不合适的,缓存了 ObjectFactory 之后,如果遇到循环依赖就调用(提前增强),没有遇到循环依赖就不调用(走正常的 Bean 的处理过程),这样是比较合理的。

singletonFactories 在什么时机缓存和移除

为什么需要 earlySingletonObjects

earlySingletonObjects 存的是已经实例化并提前执行完该 Bean 所有 BeanPostProcessor 的 Bean,但此时 Bean 还未填充,如果没有 earlySingletonObjects,下面这个场景会出现问题:

@Component
public class B {
  
    @Autowired
    private A a;
}

@Component
public class A {
  
    @Autowired
    private B b1;
  
    @Autowired
    private B b2;
}
  1. 对 A 执行填充时,先处理 b1 属性,此时 B 在 singletonObjects 不存在,所以先实例化 B,再从 singletonFactories 中查找到 B 的提前执行 BeanPostProcessor 的 ObjectFactory,调用 getObject 获取到提前执行 BeanPostProcessor 的增强 B 实例,注入到 b1 属性中;
  2. 到了 b2 这个属性时,由于 B 在 singletonObjects 中还是不存在,所以仍然需要获取 B 的 ObjectFactory,执行 getObject,导致又对 B 执行了一遍 BeanPostProcessor。

所以为了处理多次引用的问题,需要这个中间状态的缓存容器 earlySingletonObjects,用来缓存实例化之后又提前执行了 BeanPostProcessor 的 Bean,此时 b2 可以直接从 earlySingletonObjects 中去获取,不会重复执行 ObjectFactory 的 getObject 方法。

earlySingletonObjects 在什么时机缓存和移除

如何避免 BeanPostProcessor 重复执行

结合 Spring 对 Bean 的处理过程,在解决循环依赖的时候,Bean 在填充阶段,已经提前执行了 singletonFactories 中的「对该 Bean 提前执行所有的 BeanPostProcessor」方法,但在 Bean 初始化时还会再次执行 BeanPostProcessor,所以会导致执行两次。

Spring 提供了 SmartInstantiationAwareBeanPostProcessor 接口,需要增强 Bean 的 BeanPostProcessor 可以实现此接口, 并增加一个缓存,用来存储已经增强的 Bean ,每次调用该 BeanPostProcessor 的时候,如果缓存中已经存在那就说明创建过了,直接返回上次创建的即可,避免重复增强。

Spring 无法解决什么场景的循环依赖

构造器注入的场景无法解决,因为构造器注入的时候 Bean 还未完成实例化,更别提放入缓存了,没放入缓存就无法解决循环依赖问题。

setter 注入平日不使用,不做研究。

举个栗子🌰

结合一个具体的场景,A 和 B 互相依赖,处理过程如下:

@Component
public class A {
    @Autowired
    private B b;
}

@Component
public class B {  
    @Autowired
    private A a;
}
  1. 开搞,此时缓存中啥也没有

    singletonObjects(一级) earlySingletonObjects(二级) singletonFactories(三级)
         
  2. 缓存中不存在 A,所以实例化 A,生成了 a1 对象,在三级缓存中添加对 a1 执行所有 BeanPostProcessor 的延迟处理

    singletonObjects(一级) earlySingletonObjects(二级) singletonFactories(三级)
        A → ObjectFactory(a1)
  3. 对 a1 进行填充,发现了 B 的引用,要对 a1 中的 b 对象进行注入,同样地缓存中不存在 B,也是先实例化 B,生成了 b1 对象,在三级缓存中添加对 b1 执行所有 BeanPostProcessor 的延迟处理

    singletonObjects(一级) earlySingletonObjects(二级) singletonFactories(三级)
        A → ObjectFactory(a1)
    B → ObjectFactoty(b1)
  4. 对 b1 进行填充,发现了 A 引用,前两级缓存中没有 A,三级缓存中找到了 A 的 ObjectFactory 并执行,将返回的结果 Proxy$a1(增强后的a1) 放入二级缓存中,同时在三级缓存中移除 A

    singletonObjects(一级) earlySingletonObjects(二级) singletonFactories(三级)
      A → Proxy$a1 B → ObjectFactoty(b1)
  5. Proxy$a1 注入到 b1 对象的 a 属性,B 填充完成,执行初始化、BeanPostProcessor 后,完成创建单例过程,放入一级缓存中,移除 B 的三级缓存

    注意:如果 BeanPostProcessor 有增强 b1,则一级缓存中缓存的为 Proxy$b1,否则为 b1

    ingletonObjects(一级) earlySingletonObjects(二级) singletonFactories(三级)
    B → Proxy$b1 A → Proxy$a1  
  6. Proxy$b1 注入到 a1 的 b 属性,a1 对象填充完毕,执行初始化、BeanPostProcessor,因为有 SmartInstantiationAwareBeanPostProcessor 的存在,最终增强后的对象仍然是 Proxy$a1,完成 A 的单例创建,添加到一级缓存,从二级缓存中移除

    ingletonObjects(一级) earlySingletonObjects(二级) singletonFactories(三级)
    B → Proxy$b1
    A → Proxy$a1
       
  7. 两个对象创建完毕