SpringIOC容器初始化–createBean(

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

1.前言

本文主要讲解 protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException 方法。
这个方法的作用就是:创建bean实列,填充bean实例,执行该bean的 后置处理器(post-processors)

2. createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

接下来我们跟着源码看看详细过程
create.jpg
这里首先定义一个 mbdToUse 变量用作mbd 的副本

2.1 resolveBeanClass(mbd, beanName);

这个方法主要作用是:解析beanName 对应的类型 并返回。如:com.lcx.serviece.TestServiceImpl

图片.png
图片.png
1.首先判断 mbd.beanClass 是否属于 Class,若属于则直接返回 mbd.beanClass.
2.判断当前系统安全策略管理器是否为null,若不为null,则给里面代码一个特权,绕过权限检查。
3.这里的核心主要是调用 doResolveBeanClass(mbd, typesToMatch)

2.1.1 doResolveBeanClass(mbd, typesToMatch)

private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
      throws ClassNotFoundException {
   // 获取当前容器的类加载器
   ClassLoader beanClassLoader = getBeanClassLoader();
   // 创建一份副本
   ClassLoader dynamicLoader = beanClassLoader;
   // 表示mdb的配置的bean类名需要重新被dynameicLoader加载的标记,默认不需要
   boolean freshResolve = false;
   //当传过来的 类型 typesToMatch 不为null时
   if (!ObjectUtils.isEmpty(typesToMatch)) {
      // When just doing type checks (i.e. not creating an actual instance yet),
      // use the specified temporary class loader (e.g. in a weaving scenario).
      // 获取当前容器的 临时类型加载器
      ClassLoader tempClassLoader = getTempClassLoader();
      if (tempClassLoader != null) {
        //临时类型加载器 不为null 时,把它赋给 dynamicLoader
         dynamicLoader = tempClassLoader;
         freshResolve = true;
         //如果tempClassLoader 是 DecoratingClassLoader 的基类
         if (tempClassLoader instanceof DecoratingClassLoader) {
             // 类型转换 把tempClassLoader 转成DecoratingClassLoader(装饰类加载器)
            DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
            // 在dcl中排除 typesToMatch中包含的类型
            for (Class<?> typeToMatch : typesToMatch) {
               dcl.excludeClass(typeToMatch.getName());
            }
         }
      }
   }
    // 返回当前bean 的 类名 ,源代码见图2.1
   String className = mbd.getBeanClassName();
   if (className != null) {
      // 评估BeanDefinition 中包含的className,如果className 是可解析的表达式,会对其解析,否则直接返回 源码见图 2.2 
      Object evaluated = evaluateBeanDefinitionString(className, mbd);
      // 如果它两不一样则说明 className 是可解析的字符串。
      if (!className.equals(evaluated)) {
         // A dynamically resolved expression, supported as of 4.2...
         // 如果解析后的 evaluated 是 Class类型的实例
         if (evaluated instanceof Class) {
             // 则可以直接返回
            return (Class<?>) evaluated;
         }
         else if (evaluated instanceof String) {
         // 如果它是String 类型,则把它赋给 className
            className = (String) evaluated;
            freshResolve = true;
         }
         else {
            throw new IllegalStateException("Invalid class name expression result: " + evaluated);
         }
      }
      // 当freshResolve == true  表示它需要被 dynamicLoader 重新加载时 进入
      if (freshResolve) {
         // When resolving against a temporary class loader, exit early in order
         // to avoid storing the resolved Class in the bean definition.
         if (dynamicLoader != null) {
            try {
                // 返回类加载器,重新加载后的对象 源码见图 2.3
               return dynamicLoader.loadClass(className);
            }
            catch (ClassNotFoundException ex) {
               if (logger.isTraceEnabled()) {
                  logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex);
               }
            }
         }
         // dynamicLoader 加载失败,则会调用 下面这个方法重新加载
         return ClassUtils.forName(className, dynamicLoader);
      }
   }

   // Resolve regularly, caching the result in the BeanDefinition...
   // 定期解析,将结果缓存在 BeanDefinition 中
   // 这里也是通过 beanClassLoader 解析 该BeanDefinition 中 定义的 class,最后将结果保存在 beanClass中,下次可通过getBeanClass() 方法直接获取
   return mbd.resolveBeanClass(beanClassLoader);
}
复制代码

图2.1:图片.png
这里看见它会先直接取出 当前bean 对应的 beanDefinition 的 beanClass,如果它是一个 Class 的实例,则调用它的getName() 方法返回,否则直接把它转成字符串 返回。这里如果 beanClass 为null 后续调用 mbd.resolveBeanClass(beanClassLoader) 就会把结果缓存到 beanClass 中去。

图2.2: 图片.png
这里面主要讲的 SPEL 表达式的解析,具体内容我给它单独放了一篇文章,感兴趣的可以看看。

图2.3:这里主要就是加载这个类(双亲委派机制)
图片.png
图片.png

  • 首先它会检查这个类有没有加载,如果没有加载,它会获取父类加载器,当父类加载器不为null时,调用父类加载器的加载方法,若父类加载器为null,则获取系统类加载器,来加载该类。如果还是没有加载到则一层层向下加载
  • 加载完成后 如果需要解析该类,则解析一下 返回

这里比较重要后续有时间的话,可以再详细讲讲 类加载器。

ClassUtils.forName(className, dynamicLoader) : 这个方法主要是Spring 用来替换 Class.forName()的方法,主要作用也是加载类,后面有时间我会在详细的讲下。

2.2

图片.png
图片.png
这里主要判断,当上一步解析的 resolvedClass 不为null,且 mbd的beanClass 不是Class 类型,且它的beanClass 不为null。
就会克隆一份 mbd 的副本,取代mbd后续的操作,设置mbdToUse的beanClass.

2.3 mbdToUse.prepareMethodOverrides()

这个方法的主要作用就是验证 准备方法重写,源码如下:
图片.png
图片.png

  1. 首先检查 当前 beanDefinition 的 methodOverrides 是不是null
  2. 若不为null,取出当前 methodOverrides 中所有的 methodOverride 遍历调用 prepareMethodOverride() 方法。
    图片.png
    图片.png
  3. prepareMethodOverride(),源码如下:
    图片.png

    • 首先统计指定类中匹配该方法名称的方法个数,包括非public方法,因为已经进来了,所以它匹配的方法数不可能为0,当它为0时 抛出异常,当它为1时,说明它是重写的方法,不可能包含重载,这里将覆盖标记为未重载,以避免arg类型检查的开销。
    • getMethodCountForName 方法:
      图片.png

      1. 现获取 clazz 的所有方法,拿着他们的名字和 methodName 对比 如果相同则 count++;
      2. 获取clazz 所实现的所有接口,遍历每一个接口,递归调用当前方法, count = count+递归的返回值
      3. 获取 clazz 的父类,接着递归调用当前方法,count = count+递归的返回值
      4. 返回count

2.4 resolveBeforeInstantiation(beanName, mbdToUse)

这里它的作用就是:让BeanPostProcessors有机会返回一个代理而不是目标bean实例。 如果能拿到代理对象就直接返回,否则就调用下面的 doCreateBean(beanName, mbdToUse, args)
图片.png

  • 首先判断 是否被解析过了 默认false
  • mbd.isSynthetic(): 返回当前bean definition 是否是合成的
  • hasInstantiationAwareBeanPostProcessors(): 返回此工厂是否拥有实例化WareBeanPostProcessor
  • determineTargetType方法:确定 bean definition 定义的目标类型 源码如下:
    图片.png
  • 如果targetType 不为 null 时 调用 applyBeanPostProcessorsBeforeInstantiation(targetType, beanName) 获取 bean,若bean 不为null 接着调用 applyBeanPostProcessorsAfterInitialization(bean, beanName)。
  • 如果bean 不为null 说明 他已经被解析过了,mbd.beforeInstantiationResolved 置为 true。直接返回result。

1. applyBeanPostProcessorsBeforeInstantiation(targetType, beanName)

图片.png

  • 拿到当前容器的 beanPostProcessors 进行遍历。
    图片.png
  • 判断 如果该 BeanPostProcessor 是 InstantiationAwareBeanPostProcessor 的实例,则调用postProcessBeforeInstantiation 方法。
  • postProcessBeforeInstantiation 方法:用于在 Bean 实例化之前调用。如果该方法返回的值不为空的话,则直接将该对象作为创建的 bean 返回给 spring 容器。

2. applyBeanPostProcessorsAfterInitialization(bean, beanName)

图片.png

  • 先拿到当前容器的 beanPostProcessors 进行遍历
  • 遍历执行它们的 postProcessAfterInitialization 方法。若返回值为null 直接返回result,否则把 生成的 current 赋给 result.
  • postProcessAfterInitialization 方法:在bean 实例化后调用,通常用于给bean设置属性信息,如果返回值不为null,一直往后调用 BeanPostProcessor#postProcessAfterInitialization ,一旦返回null,则直接返回 result

2.5 doCreateBean(beanName, mbdToUse, args);

执行了前面四步,仍旧没有返回,就会调用这个方法,它的主要作用:真正创建指定bean的代码,不过在这之前,它需要完成预创建处理 比如:检查{@code postProcessBeforeInstantiation}回调。
这个方法设计到创建bean的具体细节,本篇文章讲不完,后续我会单独来讲。