Spring IOC容器初始化原理分析 (第六节上)

1,151 阅读9分钟

「这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战

1.前言

本文主要讲Spring IOC容器初始化过程中的 finishBeanFactoryInitialization(beanFactory) 方法,如想看之前的内容可查看 Spring IOC容器初始化原理分析 (第五节)

finishBeanFactoryInitialization(beanFactory) 是在Spring IOC 容器初始化过程中 refresh()中调用的,它的主要作用是实例化所有非懒加载的单实例bean

2.refresh()源码

如果需要复制代码,可前往Spring IOC容器初始化原理分析 (第一节)

refresh.jpg

3.finishBeanFactoryInitialization(beanFactory) 源码

2021-11-13_103149.jpg

3.1 第一步详解

这里先把变量的源码贴一下

图片.png 所以到这里 第一步的作用就很简单明了了,先判断 beanFactory 中 是否包含一个名为 conversionService 的bean 且 它的类型是 ConversionService.class 如果有的话,就把它设置到 beanFactory 的 conversionService属性中去。 ConversionService.class是一个用于系统类型转换的接口,我们可以实现它,自定义一些类型转换方式。

3.2 第二步详解

hasEmbeddedValueResolver 的默认实现如下图 图片.png 图片.png 其实这步的主要作用就是判断 embeddedValueResolvers 中是否有 StringValueResolver 对象,如果没有的话,给它注册一个默认的 StringValueResolver 对象,这里StringValueResolver 的作用主要用用来解析注解中字符串的属性值。

3.3第三步详解

这步的主要作用就是,初始化所有的 LoadTimeWeaverAware ,以便尽早的注册它们的转换器。LoadTimeWeaverAware 的主要作用是 在加载sring bean 织入第三方模块,这和spring aop 相关。这里就先不细讲了,想了解的话大家可以官网扒一扒。

3.4 第四步详解

这步作用比较直接:停止使用临时类加载器进行类型匹配,即把临时类型加载器设为null

3.5 第五步详解

缓存所有的bean定义的元数据,不希望后面还修改,即bean 即将被实例化,不希望它的数据被修改。源码如下:

图片.png

4.preInstantiateSingletons() (第六步)

这步的作用就是实例化所有剩余的 非懒加载的单实例bean,接下来我们一步步分析下它的实例化过程

public void preInstantiateSingletons() throws BeansException {
    // 日志记录
   if (logger.isTraceEnabled()) {
      logger.trace("Pre-instantiating singletons in " + this);
   }

   // Iterate over a copy to allow for init methods which in turn register new bean definitions.
   // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
   // 创建this.beanDefinitionNames 的副本用于后续的遍历,以允许 init方法注册新的bean定义
   List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

   //触发所有非懒加载的单例bean的初始化
   // 遍历所有的 beanName
   for (String beanName : beanNames) {
       // 根据beanName获取对应的MergedBeanDefinition 这个方法作用 我在4.1中细讲,大家可以往下看
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
      // 判断当它 非抽象,单例,非懒加载 的时候进入
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
          // 判断是否是FactoryBean 这个方法 4.2 中细讲
         if (isFactoryBean(beanName)) {
             // 得到对应的bean  这个我们会在4.4中 细讲
            Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
            // 当 bean是 FactoryBean 类型时,转换一下它的类型
            if (bean instanceof FactoryBean) {
               final FactoryBean<?> factory = (FactoryBean<?>) bean;
               // 它表示,是否立即初始化的标识
               boolean isEagerInit;
               // 这一部分主要是判断它是否需要立即初始化。
               if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                   // 这个我们在 4.5 中说一下
                  isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
                              ((SmartFactoryBean<?>) factory)::isEagerInit,
                        getAccessControlContext());
               }
               else {
                  isEagerInit = (factory instanceof SmartFactoryBean &&
                        ((SmartFactoryBean<?>) factory).isEagerInit());
               }
               if (isEagerInit) {
                  getBean(beanName);
               }
            }
         }
         else {
            getBean(beanName);
         }
      }
   }

   // Trigger post-initialization callback for all applicable beans...
   // 遍历所有的 beanName , 为属于 SmartInitializingSingleton 这种类的bean 执行初始化后回调
   // 这里bean 已经实例化完成
   for (String beanName : beanNames) {
       // 拿到beanName 的bean 实例 这里4.3 中细讲
      Object singletonInstance = getSingleton(beanName);
      // 判断是否属于 SmartInitializingSingleton
      if (singletonInstance instanceof SmartInitializingSingleton) {
         final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
         // 执行 SmartInitializingSingleton实现类的afterSingletonsInstantiated方法
         // 实例化后的回调方法,
         if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
               smartSingleton.afterSingletonsInstantiated();
               return null;
            }, getAccessControlContext());
         }
         else {
            smartSingleton.afterSingletonsInstantiated();
         }
      }
   }
}

4.1 getMergedLocalBeanDefinition(beanName) 方法

在讲这个方法前,先简单了解一下 BeanDefintion,Spring容器启动的过程中,会将Bean解析成Spring内部的BeanDefinition结构。 BeanDefinition描述了一个bean的实例,包括属性值,构造方法参数值和继承自它的类的更多信息以及bean 的作用域,是否懒加载等 创建这个bean 所需要的所有信息。这里我就简单说一下。

图片.png

  • AbstractBeanDefinition:抽象类,实现了BeanDefinition的部分方法。方便子类继承
  • AnnotatedBeanDefinition:注解类型的 BeanDefinition
  • RootBeanDefinition:父级 BeanDefinition
  • ChildBeanDefinition:子级 BeanDefinition,必须设置 parentName 即父级 BeanDefinition的信息
  • GenericBeanDefinition:一般的 BeanDefinition

mergedBeanDefinitions:hashMap key是beanName,value是 RootBeanDefinition 图片.png 图片.png 这个方法的官方定义是:返回合并的RootBeanDefinition,如果指定的bean对应于子bean定义,则遍历父bean定义。

图片.png 这里先取到 RootBeanDefinition mbd,判断当他,不为空,且不需要重新合并定义的时候直接返回(ps: 这里的stale表示是否需要是否需要重新合并定义) 否则的话调用

图片.png 首先先说一下 getBeanDefinition(beanName) :即根据名称从 beanDefinitionMap 取出对应 BeanDefinition

图片.png 图片.png 接着再来讲getMergedBeanDefinition(beanName, getBeanDefinition(beanName)) 图片.png 接着往下追

protected RootBeanDefinition getMergedBeanDefinition(
      String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
      throws BeanDefinitionStoreException {
  // 首先加把锁 保证在执行这个方法时,别的线程不可以修改mergedBeanDefinitions
   synchronized (this.mergedBeanDefinitions) {
      RootBeanDefinition mbd = null;
      RootBeanDefinition previous = null;

      // Check with full lock now in order to enforce the same merged instance.
      // 判断 containingBd为空时 进入
      if (containingBd == null) {
          // 从 mergedBeanDefinitions(Map) 中取出 RootBeanDefinition (此时mbd类型是RootBeanDefinition,也可能为null)
         mbd = this.mergedBeanDefinitions.get(beanName);
      }
      // 当 mbd 为null 或者 需要重新合并定义时
      if (mbd == null || mbd.stale) {
          // 记录mbd 当前的引用信息
         previous = mbd;
         // 置为null
         mbd = null;
         
         //当bd.getParentName() == null时,如果bd 是 RootBeanDefinition,把bd拷贝给 mbd,
         // 这里比 mbd = new RootBeanDefinition(bd); 多拷贝了一些属性 代码贴在 下面图1
         if (bd.getParentName() == null) {
            // Use copy of given root bean definition.
            if (bd instanceof RootBeanDefinition) {
               mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
            }
            else {
               mbd = new RootBeanDefinition(bd);
            }
         }
         // 当bd.getParentName() != null时,说明它是一个Child BeanDefinition 需要与父节点进行合并
         else {
            // Child bean definition: needs to be merged with parent.
            BeanDefinition pbd;
            try {
            // transformedBeanName:返回bean名称,必要时去掉工厂解引用前缀,并将别名解析为规范名称。
               String parentBeanName = transformedBeanName(bd.getParentName());
               // 如果beanName不等于parentBeanName
               if (!beanName.equals(parentBeanName)) {
               // 返回给定bean名称的合并的 BeanDefinition,必要时将子BeanDefinition与其BeanDefinition合并。 这里放在 下面图二补充
                  pbd = getMergedBeanDefinition(parentBeanName);
               }
               else {
               // 否则的话 先取得 当前对象的parentBeanFactory,判断当它属于 ConfigurableBeanFactory
                  BeanFactory parent = getParentBeanFactory();
                  if (parent instanceof ConfigurableBeanFactory) {
                  // 强转一下 调用 getMergedBeanDefinition 和上面相同 具体解释如下面图二
                     pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
                  }
                  else {
                  // 否则的话 抛出异常
                     throw new NoSuchBeanDefinitionException(parentBeanName,
                           "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
                           "': cannot be resolved without an AbstractBeanFactory parent");
                  }
               }
            }
            catch (NoSuchBeanDefinitionException ex) {
               throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
                     "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
            }
            // Deep copy with overridden values.
            //深层次复制,具体如图一
            mbd = new RootBeanDefinition(pbd);
            // 属性覆盖,具体看图三,使用原始的bd信息,覆盖父级信息
            mbd.overrideFrom(bd);
         }

         // Set default singleton scope, if not configured before.
         //判断 mbd的作用域 如果没有 默认给单例
         if (!StringUtils.hasLength(mbd.getScope())) {
            mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
         }

         // A bean contained in a non-singleton bean cannot be a singleton itself.
         // Let's correct this on the fly here, since this might be the result of
         // parent-child merging for the outer bean, in which case the original inner bean
         // definition will not have inherited the merged outer bean's singleton status.
         // 包含在非单例Bean中的Bean本身不能是单例的。
         // 让我们在此即时进行更正,因为这可能是外部bean的父子合并的结果,在这种情况下,
         // 原始内部bean定义将不会继承合并的外部bean的单例状态。
         // 如果有传包含bean定义且包含bean定义不是单例但mbd又是单例
         if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
            //设置mbd的作用域 和 containingBd的作用域 一样
            mbd.setScope(containingBd.getScope());
         }

         // Cache the merged bean definition for the time being
         // (it might still get re-merged later on in order to pick up metadata changes)
         //暂时缓存合并bean定义
         //稍后它可能仍然可以重新合并,以便拾取元数据变更
         if (containingBd == null && isCacheBeanMetadata()) {
         // 当containingBd为null 且 this.cacheBeanMetadata == true 把合并后的BeanDefinitions重新放到 this.mergedBeanDefinitions 中去
            this.mergedBeanDefinitions.put(beanName, mbd);
         }
      }
      if (previous != null) {
      //如果previose 不为null , 把 previous 的部分属性 设置给 mbd ,具体属性看图四
         copyRelevantMergedBeanDefinitionCaches(previous, mbd);
      }
      return mbd;
   }
}

图一(多张):

2021-11-13_155417.jpg

2021-11-13_155640.jpg

2021-11-13_164115.jpg

图二(多张): 图片.png 图片.png 这里实际是通过 得到的 parentBeanName ,先判断当容器中的 beanDefinitionMap不包含它时且 this.parentBeanFactory instanceof ConfigurableBeanFactory 时 在调用本身。否则的话 再走一遍4.1的流程

图三:

2021-11-13_163742.jpg

图四:

图片.png

4.2 isFactoryBean(beanName) 源码如下

图片.png 1.先取得最终的beanName,然后拿着这个名字,调用getSingleton(beanNama,false)方法,返回单例对象。 这里 getSingleton 在 4.3 中有详细讲到

  1. beanInstance 不为null 时直接返回 beanInstance instanceof FactoryBean ,否则的话就说明这个beanName对应的bean还没有实例化,则先判断当容器中的 beanDefinitionMap不包含它时且 this.parentBeanFactory instanceof ConfigurableBeanFactory 时 接着判断。

3.isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName))

图片.png 图片.png 图片.png 图片.png 先取出 mbd的isFactoryBean,当它不是null的时候直接返回,否则调用 predictBeanType

  • predictBeanType:获取 targetType
    • getTargetType: 如果已知,返回此bean定义的目标类型,当根据它的 targetType 返回 如果targetType 不为null 直接返回,否则的话 判断 this.factoryMethodName 不为空时返回resolveBeanClass(mbd, beanName, typesToMatch),这个方法的主要作用:解析指定bean定义的bean类,将bean类名解析为class引用(如果需要),并将解析后的class存储在bean定义中以供进一步使用。这里就不往下继续讲了

4.3 getSingleton(beanName)

主要作用: 获取该beanName 下注册的单实例对象。 源码如下: 图片.png 图片.png 图片.png 图片.png 图片.png 图片.png 图片.png this.singletonObjects(一级缓存)是一个Map 缓存了所有实例化好的单例对象,对象名--》对象,从里面拿出这个对象。

  • 如果不为null,则直接返回。
  • 否则判断当前正在创建的bean中是否有它(this.singletonsCurrentlyInCreation 保存当前正在创建的对象的名称,也就是没有初始化完成(比如A的构造器依赖了B对象所以得先去创建B对象, 或者在A的populateBean过程中依赖了B对象,得先去创建B对象,这时的A就是处于创建中的状态。)
    • 如果没有直接返回
    • 如果有则从this.earlySingletonObjects(二级缓存,保存提前曝光的单例对象:beanName -->bean实例) 中取出
      • 当 allowEarlyReference=false 直接返回.
      • 否则从 this.singletonFactories (三级缓存,保存的是要被实例化的对象的对象工厂 beanName --> ObjectFactory):取出 ObjectFactory 当它不为空的时候 从这里面取到 singletonObject,顺便把它从 singletonFactories 中移除,把它添加到 earlySingletonObjects 中,最终返回 singletonObject.

这里这种设计思想(三级缓存),实际上帮我们解决,单例模式下setter循环依赖的问题(即通过属性相互依赖的问题,构造器依赖spring解决不了) 例如有两个类,A和B ,A中有个属性是B,B中有个属性是A,spring 在初始的时候,先初始A 对象,当A完成初始化的第一步时(此时构造器放在已经执行完成),spring 会将它放在 singletonFactories 中 (具体的初始化过程下篇再讲),然后准备继续往下执行的时候,A 发现 它依赖B对象,A会从容器中尝试获取B,当A没有获取到的时候,就会转而先去创建B对象,B执行完构造器方法后,接着往下执行,发现自己依赖A。于是尝试获取A,从 一级缓存singletonObjects中获取(没有,因为A还没初始化完全),从二级缓存earlySingletonObjects中获取 (也没有),尝试三级缓存singletonFactories中获取,因为A通过ObjectFactory将自己提前曝光了,所以B可以获取到A(虽然没有初始化完全,但是能获取到),然后B完成自己的初始化过程,然后A接着完成自己的初始化过程

5.小结

本来想一篇弄完的,结果发现东西太多了,下篇文章我在继续补,下篇文章主要讲这个的后续的 4.3 getBean()和后面的方法。