spring源码-第四个后置处理器

这是第四个后置处理器的源码学习笔记
第四个后置处理器,主要是为了完成对循环依赖的支持

org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference

这是第四个后置处理器的方法名,在spring源码中,实现了该方法的,只有两个beanPostProcessor,分别是:

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getEarlyBeanReference

org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter#getEarlyBeanReference

其中InstantiationAwareBeanPostProcessorAdapter的getEarlyBeanReference()方法没有做什么处理,只是原封不动的把bean返回了出去
主要的功能,在AbstractAutoProxyCreator#getEarlyBeanReference这里

我们首先来看这个方法的代码

@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
    
    
  Object cacheKey = getCacheKey(bean.getClass(), beanName);
  if (!this.earlyProxyReferences.contains(cacheKey)) {
    
    
    this.earlyProxyReferences.add(cacheKey);
  }
  return wrapIfNecessary(bean, beanName, cacheKey);
}

代码只有这么几行,但是会发现,这几行代码,其实就是第八个后置处理器(生成动态代理对象)所做的事情;

接下来我们来看第四个后置处理器的外层的逻辑

/**
 * 第四个后置处理器执行的前提条件是:
 * 1.当前bean是单实例的
 * 2.当前beanFactory允许循环依赖:allowCircularReferences这个参数没找到在哪个扩展点中可以改为false,初始化默认是true,所以我们姑且认为大部分情况下这个参数都是true
 * 3.当前bean正在创建中,这里是判断是否在一个集合中
 * singletonsCurrentlyInCreation会在开始初始化之前,判断当前bean是单实例的时候,加入到集合中
 */
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
    isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
    
    
  if (logger.isDebugEnabled()) {
    
    
    logger.debug("Eagerly caching bean '" + beanName +
        "' to allow for resolving potential circular references");
  }
  /**
   * mpy 第四次调用后置处理器 获取一个提前暴露的对象 objectFactory 用来解决循环依赖
   * 这里还有一个关键的作用,可以追进去看一下,这里可能会完成动态代理对象的生成(AOP)
   * 正常情况下,AOP的动态代理是在调用org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String)的时候,才会生成(也即:第八个后置处理器)
   * 但是,如果是循环依赖的话,会在 org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference(java.lang.Object, java.lang.String) 中完成
   *
   * 所以:对于循环依赖,这里提前暴露的对象,虽然没有完成后面的初始化方法的解析(invokeInitMethod),但是完成了动态代理对象的生成
   *
   * 这里getEarlyBeanReference();不会立即执行,而是在从二级缓存中获取对象的时候,会调用该方法,在该方法中完成动态代理
   *
   */
  addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

/**
 * 这里是第四个后置处理器的逻辑
 * 在这里,会把第四个后置处理器作为一个ObjectFactory存入到一个map集合中
 * 所以这个后置处理器,并不会立即执行,而是在从map取出来的时候,会被执行,那什么时候会被取出来呢?
 * 在循环依赖中
 * Add the given singleton factory for building the specified singleton
 * if necessary.
 * <p>To be called for eager registration of singletons, e.g. to be able to
 * resolve circular references.
 * @param beanName the name of the bean
 * @param singletonFactory the factory for the singleton object
 */
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
    
    
  Assert.notNull(singletonFactory, "Singleton factory must not be null");
  synchronized (this.singletonObjects) {
    
    
    /**
     * 这里会加一层判断,如果单实例池中已经有bean对象了,就无须再插入到singletonFactories中,此时也就不存在
     * 循环依赖的问题了
     */
    if (!this.singletonObjects.containsKey(beanName)) {
    
    
      this.singletonFactories.put(beanName, singletonFactory);
      this.earlySingletonObjects.remove(beanName);
      this.registeredSingletons.add(beanName);
    }
  }
}

这里的逻辑也就是这几行代码,主要是为了属性循环依赖,那至于第四个后置处理器在什么时候会被调用呢?

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
	org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String)

/**
 *
 * singletonObjects是spring单实例池
 * 我们暂时称
 *   earlySingletonObjects为三级缓存  该map是在后面进行判断,是否允许循环依赖,如果允许,就把bean存到这个map中
 *   singletonFactories为二级缓存  在判断是单实例bean的时候,将包含bean的beanFactory存到该map中,这个map中存储的是一个生成代理对象的factory
 *   singletonObjects为一级缓存,存储的是实例化之后的bean
 *
 *   在这里,三级缓存的map保存的是从二级缓存中取到的一个对象,取到之后,从二级缓存中将bean删除
 *   这样做是为了防止重复创建,
 *
 *   在获取到依赖的对象之后,会进行一次类型校验 org.springframework.beans.factory.support.AbstractBeanFactory#isTypeMatch(java.lang.String, org.springframework.core.ResolvableType)
 *
 *   循环依赖的处理:
 *    如果A注入了B,B也注入了A;在第一次实例化A的时候,会注入A,注入A的时候,会反过来去实例化B
 */
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    
    
  Object singletonObject = this.singletonObjects.get(beanName);
  if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    
    
    synchronized (this.singletonObjects) {
    
    
      //mpy 这里只需要从二级缓存中拿一次就行,如果没有二级缓存,每次进来都需要从二级缓存get一次,影响效率
      singletonObject = this.earlySingletonObjects.get(beanName);
      if (singletonObject == null && allowEarlyReference) {
    
    
        ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
        if (singletonFactory != null) {
    
    
          /**
           * 这里getObject会调用getEarlyBeanReference(beanName, mbd, bean)方法,完成动态代理对象的生成
           * 这里为什么要调用这个方法?
           * 我的理解是这样的:在属性注入之后,还有两个后置处理器需要调用:
           *  1.applyBeanPostProcessorsBeforeInitialization   invokeInitMethod方法,也即:调用bean的初始化方法的后置处理器
           *  2.applyBeanPostProcessorsAfterInitialization  这里完成的是:代理对象的生成(比如:AOP动态代理对象生成,事务方法代理对象生成)
           *
           * 既然有了循环依赖,总要有一个bean是要先注入的,在注入
           */
          singletonObject = singletonFactory.getObject();
          this.earlySingletonObjects.put(beanName, singletonObject);
          this.singletonFactories.remove(beanName);
        }
      }
    }
  }
  return singletonObject;
}

就是这里,所以我们说第四个后置处理器是为了完成对循环依赖的处理;
在A依赖B,B依赖A的情况下,先对A对象完成动态代理对象的生成,然后在注入之后,再执行属性注入、初始化方法回调等方法;其实这里有一个点没有搞懂,为什么在循环依赖中,一定要在注入bean的时候,先完成动态代理对象的生成?

猜你喜欢

转载自blog.csdn.net/CPLASF_/article/details/111585286