Spring 源码阅读 25:单例 Bean 实例的创建过程(2)

447 阅读7分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第35天,点击查看活动详情

基于 Spring Framework v5.2.6.RELEASE

接上篇:Spring 源码阅读 24:单例 Bean 实例的创建过程(1)

前情提要

上一篇开始了 Spring 得到 RootBeanDefinition 并初始化依赖的 Bean 实例之后,创建 Bean 实例部分代码的阅读和分析,在getSingleton方法内,Spring 再次尝试了从缓存集合中获取 Bean。在createBean方法中,Spring 处理了方法覆盖相关的内容,并且调用了 InstantiationAwareBeanPostProcessor 中的处理方法,此处也是自定义 Bean 实例创建的扩展点之一。最后,Spring 会在 AbstractAutowireCapableBeanFactory 中的doCreateBean执行默认的实例创建逻辑。本文将从这个方法开始入手。

doCreateBean方法概览

以下是doCreateBean方法的代码:

方法中代码比较多,因此才用了截图的方式。Spring 通过默认方式创建 Bean 实例的过程就都在这个方法里了。我们从上到下逐步分析。

首先看第一部分代码:

// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
   instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
   instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
   mbd.resolvedTargetType = beanType;
}

这里首先会从factoryBeanInstanceCache中获取一个 BeanWrapper 类型的对象,如果获取不到,就通过createBeanInstance方法创建。后半部分的几行代码就是给之后用到的局部变量赋值。这里值得重点关注的是 BeanWrapper 接口和createBeanInstance方法。

BeanWrapper

BeanWrapper 是org.springframework.beans包中的一个重要的接口,比较底层,一般我们基于 Spring 开发项目的时候,不会接触到这个接口。它的作用,就和它的名字一样,是一个 Bean 实例的包装类,并提供了一些对 Bean 实例进行操作的功能,在 Spring 创建 Bean 实例的过程中,需要通过 BeanWrapper 进行一些操作,比如获取和设置属性值等。在之后的代码分析中,还会遇到 BeanWrapper 和它的实现类,到时候可以看看 Spring 通过它具体做了哪些工作。

createBeanInstance 方法

接下来进入createBeanInstance方法。

这个方法的代码量同样不小。

在方法的开头,Spring 获取的即将创建的 Bean 实例的类型信息,并确保能够获取到类型信息、类是public修饰的、并且没有设置可以访问非public的构造器和方法,否则抛出异常。

通过 Supplier 创建 Bean 实例

接下来是从类定义中获取instanceSupplier,这个instanceSupplier是 Supplier 类型的,如果它不是空的话,则调用obtainFromSupplier方法获取一个 BeanWrapper 并返回。

Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
   return obtainFromSupplier(instanceSupplier, beanName);
}

也就是说,这个方法是可以返回一个作为结果的 BeanWrapper 实例的。我们进去看一下:

protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) {
   Object instance;

   String outerBean = this.currentlyCreatedBean.get();
   this.currentlyCreatedBean.set(beanName);
   try {
      instance = instanceSupplier.get();
   }
   finally {
      if (outerBean != null) {
         this.currentlyCreatedBean.set(outerBean);
      }
      else {
         this.currentlyCreatedBean.remove();
      }
   }

   if (instance == null) {
      instance = new NullBean();
   }
   BeanWrapper bw = new BeanWrapperImpl(instance);
   initBeanWrapper(bw);
   return bw;
}

其实就是通过instanceSupplierget方法创建一个 Bean 实例,并将其封装到一个 BeanWrapperImpl 中并返回。

不过 BeanDefinition 中的instanceSupplier默认是空的,并且之前我们也没有进行相关的操作,因此这里的创建逻辑不会被执行。

通过工厂方法创建 Bean 实例

再回到createBeanInstance方法,判断完instanceSupplier之后,又判断了 BeanDefinition 中是不是有factoryMethodName

if (mbd.getFactoryMethodName() != null) {
   return instantiateUsingFactoryMethod(beanName, mbd, args);
}

这个factoryMethodName属性,对应的 XML 配置文件中,bean标签的factory-method配置。这个特性在日常工作中几乎用不到,因此之前没有介绍,这里简单说一下。

除了通过实现 FactoryBean 接口来实现一个创建 Bean 的工厂,也可以不实现任何接口,开发一个可以得到特定类型 Bean 的工厂类。但是,需要把工厂类中,能够生产 Bean 实例的方法名称,配置到bean标签的factory-method属性值中。

如果这个方法是一个静态方法,那么可以这样配置:

<bean id="user" class="xxx.UserFactory" factory-method="getUser" />

如果这个方法不是静态方法,则还需要创建一个工厂类的实例,可以这样配置:

<bean id="userFactory" class="xxx.UserFactory" />
<bean id="user" factory-bean="userFactory" factory-method="getUser" />

这部分不常用,大概了解一下就可以,这里也不进行更深入的分析了。

通过反射创建 Bean 实例

再看接下来的一段代码。

// Shortcut when re-creating the same bean...
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
   synchronized (mbd.constructorArgumentLock) {
      if (mbd.resolvedConstructorOrFactoryMethod != null) {
         resolved = true;
         autowireNecessary = mbd.constructorArgumentsResolved;
      }
   }
}
if (resolved) {
   if (autowireNecessary) {
      return autowireConstructor(beanName, mbd, null, null);
   }
   else {
      return instantiateBean(beanName, mbd);
   }
}

因为我们整个流程是从getBean(String name)方法开始分析,args应该是空的,而且 BeanDefinition 的resolvedConstructorOrFactoryMethod属性默认也是空的,因此,这段代码实际上是执行不到的。

不过,我们可以大概分析一下这段逻辑,这里应该是要解决构造方法中参数值自动装配的逻辑,如果需要参数的自动装配,就通过autowireConstructor方法来创建实例,如果不需要,则通过instantiateBean方法调用默认构造方法来创建实例。

接着往下看。

// Candidate constructors for autowiring?
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
      mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
   return autowireConstructor(beanName, mbd, ctors, args);
}

这里通过determineConstructorsFromBeanPostProcessors方法,获取到了 Bean 的类型中可用的构造函数。具体代码如下:

// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#determineConstructorsFromBeanPostProcessors
@Nullable
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
      throws BeansException {

   if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
            SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
            Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
            if (ctors != null) {
               return ctors;
            }
         }
      }
   }
   return null;
}

其实就是执行了特定类型的 BeanPostProcessor 的处理逻辑,也就是 SmartInstantiationAwareBeanPostProcessor 中的determineCandidateConstructors方法,它可以用来获取 Bean 的候选构造函数。然后进行判断,如果满足一系列判断条件,则执行autowireConstructor方法创建 BeanWrapper。

从写判断逻辑和autowireConstructor方法名都可以看出,这里跟构造方法的@Autowrired注解有一定关系,不在本文的讨论范围,因此,这里不做过多介绍。感兴趣的话,可以大概浏览一下方法中的逻辑,其实就是根据构造方法的参数列表信息和给定的参数值数组,将这些参数的实例获取到并调用构造方法来创建 Bean 实例,并包装到 BeanWrapper 中返回,主要使用了反射的机制。

回到createBeanInstance方法中接着往下看。

// Preferred constructors for default construction?
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
   return autowireConstructor(beanName, mbd, ctors, null);
}

这里的getPreferredConstructors默认会返回空。

// No special handling: simply use no-arg constructor.
return instantiateBean(beanName, mbd);

方法的最后,就是没有特殊处理的情况,调用了instantiateBean方法,通过无参构造方法来创建实例。方法的代码如下:

// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#instantiateBean
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
   try {
      Object beanInstance;
      final BeanFactory parent = this;
      if (System.getSecurityManager() != null) {
         beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
               getInstantiationStrategy().instantiate(mbd, beanName, parent),
               getAccessControlContext());
      }
      else {
         beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
      }
      BeanWrapper bw = new BeanWrapperImpl(beanInstance);
      initBeanWrapper(bw);
      return bw;
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
   }
}

这里可以看到,最重要的一行代码就是:

beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);

接着深入,找到instantiate方法。

// org.springframework.beans.factory.support.SimpleInstantiationStrategy#instantiate(org.springframework.beans.factory.support.RootBeanDefinition, java.lang.String, org.springframework.beans.factory.BeanFactory)
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
   // Don't override the class with CGLIB if no overrides.
   if (!bd.hasMethodOverrides()) {
      Constructor<?> constructorToUse;
      synchronized (bd.constructorArgumentLock) {
         constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
         if (constructorToUse == null) {
            final Class<?> clazz = bd.getBeanClass();
            if (clazz.isInterface()) {
               throw new BeanInstantiationException(clazz, "Specified class is an interface");
            }
            try {
               if (System.getSecurityManager() != null) {
                  constructorToUse = AccessController.doPrivileged(
                        (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
               }
               else {
                  constructorToUse = clazz.getDeclaredConstructor();
               }
               bd.resolvedConstructorOrFactoryMethod = constructorToUse;
            }
            catch (Throwable ex) {
               throw new BeanInstantiationException(clazz, "No default constructor found", ex);
            }
         }
      }
      return BeanUtils.instantiateClass(constructorToUse);
   }
   else {
      // Must generate CGLIB subclass.
      return instantiateWithMethodInjection(bd, beanName, owner);
   }
}

这里通过bd.hasMethodOverrides()判断是不是有方法覆盖。如果有的话,则通过instantiateWithMethodInjection创建结果实例,从方法名和这里的注释可以推测出,方法覆盖注入是通过cglib来实现的。因为这个特性应用得并不多,就不过多介绍了,感兴趣可以跳到方法内部看一下源码,逻辑并不复杂。

下面看if语句块中的部分。这部分的主要逻辑就是获取到当前 Bean 类型的构造器,然后交给 BeanUtils 的instantiateClass方法进行实例的创建。

// org.springframework.beans.BeanUtils#instantiateClass(java.lang.reflect.Constructor<T>, java.lang.Object...)
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
   Assert.notNull(ctor, "Constructor must not be null");
   try {
      ReflectionUtils.makeAccessible(ctor);
      if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
         return KotlinDelegate.instantiateClass(ctor, args);
      }
      else {
         Class<?>[] parameterTypes = ctor.getParameterTypes();
         Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
         Object[] argsWithDefaultValues = new Object[args.length];
         for (int i = 0 ; i < args.length; i++) {
            if (args[i] == null) {
               Class<?> parameterType = parameterTypes[i];
               argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);
            }
            else {
               argsWithDefaultValues[i] = args[i];
            }
         }
         return ctor.newInstance(argsWithDefaultValues);
      }
   }
   catch (InstantiationException ex) {
      throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
   }
   catch (IllegalAccessException ex) {
      throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
   }
   catch (IllegalArgumentException ex) {
      throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
   }
   catch (InvocationTargetException ex) {
      throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
   }
}

一套标准的反射创建对象的流程,最终,Spring 通过反射机制创建出了 Bean 的实例。

总结

通过本文的分析,终于走到了 Spring 最终把 Bean 实例创建出来的,这个实例会被一个 BeanWrapper 类型的对象包装,并返回到doCreateBean方法中,不过,在doCreateBean方法中,这才只完成了第一步,后面还有更多的处理流程。