【Spring Bean生命周期】高手如何解读源码(二) - Bean的生命周期

377 阅读7分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天
Spring Bean生命周期,从入门到进阶:
【Spring Bean生命周期】小白也能看懂的入门篇
【Spring Bean生命周期】高手如何解读源码(一)-资源的扫描和注册

1 Bean生命周期的核心动作

  上一节讲了第一部分Bean的扫描以及注册,本文主要讲解第二部分Spring Bean生命周期,主要包含下面四个主要动作:

  • 实例化 Instantiation
  • 属性赋值 Populate
  • 初始化 Initialization
  • 销毁 Destruction

image.png   依照黄金圈法则(why->what->how),在去了解Spring是如何实现之前,我们先了解下为什么要有这些动作?

我们知道,普通Java类是先初始化->再实例化的:

类的初始化:是完成程序执行前的准备工作。在这个阶段,静态的(变量,方法,代码块)会被执行。同时在会开辟一块存储空间用来存放静态的数据。初始化只在类加载的时候执行一次。

类的实例化:是指创建一个对象的过程。这个过程中会在堆中开辟内存,将一些非静态的方法,变量存放在里面。在程序执行的过程中,可以创建多个对象,既多次实例化。每次实例化都会开辟一块新的内存

而Spring Bean是先实例化->再初始化:

Bean的实例化:等同于 类的实例化

Bean的初始化:是完成Bean使用前的准备工作。主要包含 执行Aware相关接口的set方法注入依赖,执行BeanPostProcessors的前置方法,@PostConstruct注解方法执行,InitializingBean接口实现类(组件)的初始化方法afterPropertiesSet执行,自己指定的init-method方法执行等

一句话理解,初始化是在为正式使用做准备,类初始化的结果是Jvm可用,Bean初始化的结果是用户程序可用。

  接着上文,Bean生命周期触发点,在AbstractApplicationContext类的refresh()方法中,执行到finishBeanFactoryInitialization(beanFactory)时完成Bean生命周期的动作。该方法会实例化所有剩余的非懒加载单例 bean。除了:

  • 一些内部的 bean
  • 实现了 BeanFactoryPostProcessor 接口的 bean、
  • 实现了 BeanPostProcessor 接口的 bean,
  • 其他的非懒加载单例 bean
    都会在这个方法中被实例化,并且 BeanPostProcessor 的触发也是在这个方法中。我们看下代码执行路径:
// ConfigurableListableBeanFactory接口 
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    ......
   // Instantiate all remaining (non-lazy-init) singletons.
   beanFactory.preInstantiateSingletons();
}

// DefaultListableBeanFactory类
@Override
public void preInstantiateSingletons() throws BeansException {
   
   List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

   // 触发所有非惰性Bean的初始化
   for (String beanName : beanNames) {
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
         if (isFactoryBean(beanName)) {
            Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
            if (bean instanceof FactoryBean) {
               FactoryBean<?> factory = (FactoryBean<?>) bean;
               ......
               if (isEagerInit) {
                  getBean(beanName);
               }
            }
         }
         else {
            getBean(beanName);
         }
      }
   }
......

可以看到核心方法有两个:
方法一:getMergedLocalBeanDefinition(beanName), 将前面扫描获取的各种BeanDefinition子类统一转化成RootBeanDefinition类型,作为实例化的入口。

比较常见的:
    如果我们使用 XML 配置来注册 bean,则该 bean 定义会被封装成:GenericBeanDefinition;
    如果我们使用注解的方式来注册 bean,也就是<context:component-scan /> +  **@Compoment,则该 bean 定义会被封装成 ScannedGenericBeanDefinition。**

方法二:getBean(beanName),包括Bean的实例化,属性注入和初始化等动作。

// AbstractBeanFactory类
@Override
public Object getBean(String name) throws BeansException {
   return doGetBean(name, null, null, false);
}

其中getBean()的流程如图: image.png

// AbstractAutowireCapableBeanFactory类
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 替换成自己的代理Bean 
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
......
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}

其中,resolveBeforeInstantiation()是用来触发我们预埋的实例化之前的扩展点的:


/**
 * Apply before-instantiation post-processors, resolving whether there is a
 * before-instantiation shortcut for the specified bean.
 */
@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
   Object bean = null;
   if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
      // Make sure bean class is actually resolved at this point.
      if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
         Class<?> targetType = determineTargetType(beanName, mbd);
         if (targetType != null) {
            bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
            if (bean != null) {
               bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
            }
         }
      }
      mbd.beforeInstantiationResolved = (bean != null);
   }
   return bean;
}

  可以看到,这边是把实例化->初始化当成原子操作的,即:如果已经实例化,那么就直接执行初始化之后的回调,否则执行实例化之前的回调

image.png

Spring预留的扩展点我们点到为止,还是主要来看下Bean实例化的过程.

/**
 * 实际创建Bean实例。在执行这个动作之前,postProcessBeforeInstantiation已经被执行过。
 */
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {

   // 1 实例化
   if (instanceWrapper == null) {
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }

    synchronized (mbd.postProcessingLock) {
     // 合并BeanDefinition信息,如果bean实现了MergedBeanDefinitionPostProcessor接口,会将各种类型的BeanDefinition子类转变为RootBeanDefinition类型。
      applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
    }
   ......省略 循环依赖部分 
   try {
       // 2 属性注入
      populateBean(beanName, mbd, instanceWrapper);
      // 3 初始化
      exposedObject = initializeBean(beanName, exposedObject, mbd);
   }
   catch (Throwable ex) {
   }
   ......省略 循环依赖部分
}

可以看到整个doCreateBean()逻辑分三步完成:

  1. 实例化 instanceWrapper = createBeanInstance(beanName, mbd, args);
  2. 属性注入 populateBean(beanName, mbd, instanceWrapper);
  3. 初始化 exposedObject = initializeBean(beanName, exposedObject, mbd);

第一步:实例化(Instantiation)

Spring Bean的实例化采用模板方法,实例化步骤为: Supplier获取->工厂方法获取->反射生成


/**
 * Create a new instance for the specified bean, using an appropriate instantiation strategy:
 * factory method, constructor autowiring, or simple instantiation.
 */
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
   // 1 Make sure bean class is actually resolved at this point.
   Class<?> beanClass = resolveBeanClass(mbd, beanName);

   // 2 如果提供了Supplier,通过Supplier产生对象
   Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
   if (instanceSupplier != null) {
      return obtainFromSupplier(instanceSupplier, beanName);
   }
   
   // 3 如果提供了工厂方法,则使用工厂方法产生对象,在@Configuration配置的Bean的方法,会被解析为BeanFactoryMethod
   if (mbd.getFactoryMethodName() != null) {
      return instantiateUsingFactoryMethod(beanName, mbd, args);
   }
   
   // 4 反射生成。推断构造方法
   Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
   if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
         mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
      return autowireConstructor(beanName, mbd, ctors, args);
   }

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

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

  这里提一下Supplier,它是Java里的一个函数式接口,只有一个抽象方法get(),用于返回一个对象实例。常见的stream.map(Supplier s)入参就是该类型。

第二步: 属性注入(Populate)

  本阶段完成了Spring的核心功能之一,依赖注入,在这之前我们需要先了解下什么是依赖注入。

  依赖注入(Dependency Injection, DI)是一种设计模式,也是Spring框架的核心概念之一。其作用是去除Java类之间的依赖关系,实现松耦合,以便于开发测试。    
  例如,A类要依赖B类,依赖有两个方面:
      一方面,B不能换成B1,B2等,它会影响可扩展性
      另一方面,A要负责对B实例创建销毁。那么B的修改很可能就会影响到A本身。

  我们在Spring常用到的@Autowired,为什么只是声明一下就可以直接使用,而不需要引用任何实例。我们在第一步创建好了实例,这一步就是将创建的实例注入到变量的过程。

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
   ......省略
   
   int resolvedAutowireMode = mbd.getResolvedAutowireMode();
   
   // 1 根据注入类型,自动注入到dependentBeanMap中
   if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
      MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
      // Add property values based on autowire by name if applicable.
      if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
         autowireByName(beanName, mbd, bw, newPvs);
      }
      // Add property values based on autowire by type if applicable.
      if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
         autowireByType(beanName, mbd, bw, newPvs);
      }
      pvs = newPvs;
   }

   // 2 调用BeanPostProcessor,完成@Autowired @Resource属性填充 
   PropertyDescriptor[] filteredPds = null;
   if (hasInstAwareBpps) {
      for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
         
         PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
       
      }
   }
   // 3 依赖检查
   if (needsDepCheck) {
      if (filteredPds == null) {
         filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      }
      checkDependencies(beanName, mbd, filteredPds, pvs);
   }
   // 4 将属性应用到Bean中  
   if (pvs != null) {
      applyPropertyValues(beanName, mbd, bw, pvs);
   }
}

第三步:初始化(Initialize)

  该阶段主要是对Bean做初始化操作,包括 回调Aware接口回调初始化方法生成代理对象等。

    Aware 翻译为“感知”,可以通过实现Aware接口获取容器或者Bean的某些信息,比如常见的:
    BeanNameAware: 可以获取容器中bean的名称
    BeanFactoryAware:获取当前bean factory这也可以调用容器的服务
    ApplicationContextAware:当前的applicationContext,这也可以调用容器的服务
    当Bean实现了BeanFactoryAware接口,可以通过重写setBeanFactory()方法获取到当前的BeanFactory信息。

看下初始化代码initializeBean()方法

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
   if (System.getSecurityManager() != null) {
      AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
         // 1 回调Aware方法,此处主要包含(BeanNameAware,BeanClassLoaderAware,BeanFactoryAware)
         invokeAwareMethods(beanName, bean);
         return null;
      }, getAccessControlContext());
   }
   else {
      invokeAwareMethods(beanName, bean);
   }

   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
      // 扩展点 调用postProcessBeforeInitialization()方法
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }

   try {
      // 如果Bean的方法添加了@PostConstruct注解,则会在此处调用该方法
      // 如果Bean实现了InitializingBean接口,则会在此处调用afterPropertiesSet()方法
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
   }
   if (mbd == null || !mbd.isSynthetic()) {
      // 扩展点 调用postProcessAfterInitialization()方法
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }

   return wrappedBean;
}

至此,整个Spring的IOC就构建起来了。