Spring官网阅读(十)Spring中Bean的生命周期(下)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 在上篇文章中,我们已经对Bean的生命周期做了简单的介绍,主要介绍了整个生命周期中的初始化阶段以及基于容器启动停止时LifeCycleBean的回调机制,另外对Bean的销毁过程也做了简单介绍。但是对于整个Bean的生命周期,这还只是一小部分,在这篇文章中,我们将学习完成剩下部分的学习,同时对之前的内容做一次复习。整个Bean的生命周期,按照我们之前的介绍,可以分为四部分实例化属性注入初始化销毁

生命周期概念补充


虽然我们一直说整个Bean的生命周期分为四个部分,但是相信很多同学一直对Bean的生命周期到底从哪里开始,到哪里结束没有一个清晰的概念。可能你会说,不就是从实例化开始,到销毁结束吗?当然,这并没有错,但是具体什么时候算开始实例化呢?什么时候又算销毁呢?这个问题你是否能清楚的回答呢?如果不能,请继续往下看。


笔者认为,整个Spring中Bean的生命周期,从第一次调用后置处理器中的applyBeanPostProcessorsBeforeInstantiation方法开始的,这个方法见名知意,翻译过来就是在实例化之前调用后置处理器。而applyBeanPostProcessorsAfterInitialization方法的调用,意味着Bean的生命周期中创建阶段的结束。对于销毁没有什么歧义,就是在调用对应Bean的销毁方法就以为着这个Bean走到了生命的尽头,标志着Bean生命周期的结束。那么结合上篇文章中的结论,我现在把Bean的生命周期的范围界定如下:

微信图片_20221112185331.png

需要注意的是,对于BeanDefinion的扫描,解析,验证并不属于Bean的生命周期的一部分。这样清晰的界定Bean的生命周期的概念是很有必要的,也许刚刚开始对于我们而言,Bean的生命周期就是一团乱麻,但是至少现在我们已经抓住了线头。而整个Bean的生命周期,我将其分为了两部分


  • 创建
  • 销毁

对于销毁阶段,我们不需要过多关注,对于创建阶段,开始的标志行为为:applyBeanPostProcessorsBeforeInstantiation方法执行,结束的标志行为为:applyBeanPostProcessorsAfterInitialization方法执行。


基于上面的结论,我们开始进行接下来的分析对于本文中代码的分析,我们还是参照下面这个图

微信图片_20221112185427.png

实例化


整个实例化的过程主要对于上图中的3-11-6-4(createBean)以及3-11-6-4-1(doCreateBean)步骤


createBean流程分析


代码如下:

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
    RootBeanDefinition mbdToUse = mbd;
    // 第一步:解析BeanDefinition中的beanClass属性
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
      mbdToUse = new RootBeanDefinition(mbd);
      mbdToUse.setBeanClass(resolvedClass);
    }
    try {
            // 第二步:处理lookup-method跟replace-method,判断是否存在方法的重载
      mbdToUse.prepareMethodOverrides();
    }
    catch (BeanDefinitionValidationException ex) {
      throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
          beanName, "Validation of method overrides failed", ex);
    }
    try {
      // 第三步:判断这个类在之后是否需要进行AOP代理
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      if (bean != null) {
        return bean;
      }
    }
    catch (Throwable ex) {
      throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
          "BeanPostProcessor before instantiation of bean failed", ex);
    }
    try {
            // 开始创建Bean
      Object beanInstance = doCreateBean(beanName, mbdToUse, args);
      return beanInstance;
    }
    catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
      throw ex;
    }
    catch (Throwable ex) {
      throw new BeanCreationException(
          mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
    }
  }

可以看到,第一步跟第二步还是在对BeanDefinition中的一些属性做处理,它并不属于我们Bean的生命周期的一部分,我们直接跳过,接下来看第三步的代码:

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        // 不是合成类,并且有实例化后置处理器。这个判断基本上恒成立
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            // 获取这个BeanDefinition的类型
            Class<?> targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                // 这里执行的主要是AbstractAutoProxyCreator这个类中的方法,决定是否要进行AOP代理
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                // 这里执行了一个短路操作,如果在这个后置处理中直接返回了一个Bean,那么后面相关的操作就不会执行了,只会执行一个AOP的代理操作
                if (bean != null) {
                    // 虽然这个Bean被短路了,意味着不需要经过后面的初始化阶段,但是如果需要代理的话,还是要进行AOP代理,这个地方的短路操作只是意味着我们直接在后置处理器中提供了一个准备充分的的Bean,这个Bean不需要进行初始化,但需不需要进行代理,任然由AbstractAutoProxyCreator的applyBeanPostProcessorsBeforeInstantiation方法决定。在这个地方还是要调用一次Bean的初始化后置处理器保证Bean被完全的处理完
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        // bean != null基本会一直返回false,所以beforeInstantiationResolved这个变量也会一直为false
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}

对于AbstractAutoProxyCreator中applyBeanPostProcessorsBeforeInstantiation这个方法的分析我们暂且不管,等到AOP学习阶段在进行详细分析。我们暂且只需要知道这个方法会决定在后续中要不要为这个Bean产生代理对象。


doCreateBean流程分析

  protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      throws BeanCreationException {
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
            // 第一步:单例情况下,看factoryBeanInstanceCache这个缓存中是否有
      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;
    }
    synchronized (mbd.postProcessingLock) {
      if (!mbd.postProcessed) {
        try {
                    // 第三步:后置处理器处理
          applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
        }
        catch (Throwable ex) {
          // 省略异常处理
        }
        mbd.postProcessed = true;
      }
    }
        // 循环引用相关,源码阅读阶段再来解读这段代码,暂且就关注以下后置处理器的调用时机
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
        isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
      // 第四步:调用后置处理器,早期曝光一个工厂对象
      addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }
    Object exposedObject = bean;
    try {
            // 第五步:属性注入
      populateBean(beanName, mbd, instanceWrapper);
            // 第六步:初始化
      exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    catch (Throwable ex) {
      if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
        throw (BeanCreationException) ex;
      }
      else {
        // 省略异常处理
      }
    }
    if (earlySingletonExposure) {
      Object earlySingletonReference = getSingleton(beanName, false);
      if (earlySingletonReference != null) {
        if (exposedObject == bean) {
          exposedObject = earlySingletonReference;
        }
        else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
          String[] dependentBeans = getDependentBeans(beanName);
          Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
          for (String dependentBean : dependentBeans) {
            if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
              actualDependentBeans.add(dependentBean);
            }
          }
          if (!actualDependentBeans.isEmpty()) {
            // 省略异常处理
          }
        }
      }
    }
    try {
            // 第七步:注册需要销毁的Bean,放到一个需要销毁的Map中(disposableBeans)
      registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
      // 省略异常处理
    }
    return exposedObject;
  }

第一步:factoryBeanInstanceCache什么时候不为空?

if (mbd.isSingleton()) {
    // 第一步:单例情况下,看factoryBeanInstanceCache这个缓存中是否有
    instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}

这段代码深究起来很复杂,我这里就单纯用理论解释下:

假设我们现在有一个IndexService,它有一个属性A,代码如下:

@Component
public class IndexService {
  @Autowired
  A a;
  public A getA() {
    return a;
  }
}

而这个A又是采用FactroyBean的形式配置的,如下:

@Component
public class MyFactoryBean implements SmartFactoryBean {
  @Override
  public A getObject() throws Exception {
    return new A();
  }
  @Override
  public Class<?> getObjectType() {
    return A.class;
  }
    // 这个地方并不一定要配置成懒加载,这里只是为了让MyFactoryBean这个Bean在IndexService之后实例化
  @Override
  public boolean isEagerInit() {
    return false;
  }
}

我们思考一个问题,在上面这种场景下,当IndexService要完成属性注入时,Spring会怎么做呢?


Spring现在知道IndexService要注入一个类型为A的属性,所以它会遍历所有的解析出来的BeanDefinition,然后每一个BeanDefinition中的类型是不是A类型,类似下面这样:

for (String beanName : this.beanDefinitionNames) {
  // 1.获取BeanDefinition
    // 2.根据BeanDefinition中的定义判断是否是一个A
}

上面这种判断大部分情况下是成立的,但是对于一种特殊的Bean是不行的,就是我们之前介绍过的FactoryBean,因为我们配置FactoacryBean的目的并不是直接使用FactoryBean这个Bean自身,而是想要通过它的getObject方法将一个对象放到Spring容器中,所以当我们遍历到一个BeanDefinition,并且这个BeanDefinition是一个FactoacryBean时就需要做特殊处理,我们知道FactoacryBean中有一个getObjectType方法,通过这个方法我们可以得到要被这个FactoacryBean创建的对象的类型,如果我们能调用这个方法的话,那么我们就可以来判断这个类型是不是一个A了。


但是,在我们上面的例子中,这个时候MyFactoryBean还没有被创建出来。所以Spring在这个时候会去实例化这个MyFactoryBean,然后调用其getObjectType方法,再做类型判断,最后进行属性注入,伪代码如下:

for (String beanName : this.beanDefinitionNames) {
  // 1.获取BeanDefinition
    // 2.如果不是一个FactoacryBean,直接根据BeanDefinition中的属性判断
    if(不是一个FactoacryBean){
        //直接根据BeanDefinition中的属性判断是不是A
    }
    // 3.如果是一个FactoacryBean
    if(是一个FactoacryBean){
        // 先创建这个FactoacryBean,然后再调用getObjectType方法了
    }
}

大家可以根据我们上面的代码自己调试,我这里就不放debug的截图了。


第二步:创建对象(createBeanInstance)

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // 获取到解析后的beanClass
    Class<?> beanClass = resolveBeanClass(mbd, beanName);
      // 忽略异常处理
    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
      return obtainFromSupplier(instanceSupplier, beanName);
    }
      // 获取工厂方法,用于之后创建对象 
    if (mbd.getFactoryMethodName() != null) {
      return instantiateUsingFactoryMethod(beanName, mbd, args);
    }
    // 原型情况下避免多次解析
    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);
      }
    }
    // 跟后置处理器相关,我们主要关注这行代码
    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);
    }
    // 默认使用无参构造函数创建对象
    return instantiateBean(beanName, mbd);
  }

在创建对象的时候,其余的代码我们暂时不做过多关注。我们暂且知道在创建对象的过程中,Spring会调用一个后置处理器来推断构造函数。


第三步:applyMergedBeanDefinitionPostProcessors


应用合并后的BeanDefinition,Spring自身利用这点做了一些注解元数据的缓存。

我们就以AutowiredAnnotationBeanPostProcessor这个类的对应方法看一下其大概作用

public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    // 这个方法就是找到这个正在创建的Bean中需要注入的字段,并放入缓存中
    InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
    metadata.checkConfigMembers(beanDefinition);
}

第四步:getEarlyBeanReference

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    Object exposedObject = bean;
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                // 在这里保证注入的对象是一个代理的对象(如果需要代理的话),主要用于循环依赖
                exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
            }
        }
    }
    return exposedObject;
}

属性注入


第五步:属性注入(populateBean)

  protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    if (bw == null) {
      if (mbd.hasPropertyValues()) {
        // 省略异常
      }
      else {
        return;
      }
    }
    boolean continueWithPropertyPopulation = true;
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
          InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
          if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {      // 主要判断之后是否需要进行属性注入
            continueWithPropertyPopulation = false;
            break;
          }
        }
      }
    }
    if (!continueWithPropertyPopulation) {
      return;
    }
    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
        // 自动注入模型下,找到合适的属性,在后续方法中再进行注入
    if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
      MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
      // Add property values based on autowire by name if applicable.
      if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
        autowireByName(beanName, mbd, bw, newPvs);
      }
      // Add property values based on autowire by type if applicable.
      if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
        autowireByType(beanName, mbd, bw, newPvs);
      }
      pvs = newPvs;
    }
    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
    PropertyDescriptor[] filteredPds = null;
    if (hasInstAwareBpps) {
      if (pvs == null) {
        pvs = mbd.getPropertyValues();
      }
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
          InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    // 精确注入下,在这里完成属性注入
          PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                    // 一般不会进行这个方法
          if (pvsToUse == null) {
            if (filteredPds == null) {
              filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            }
            pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
              return;
            }
          }
          pvs = pvsToUse;
        }
      }
    }
    if (needsDepCheck) {
      if (filteredPds == null) {
        filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      }
      checkDependencies(beanName, mbd, filteredPds, pvs);
    }
    if (pvs != null) {
            // XML配置,或者自动注入,会将之前找到的属性在这里进行注入
      applyPropertyValues(beanName, mbd, bw, pvs);
    }
  }

在上面整个流程中,我们主要关注一个方法,postProcessProperties,这个方法会将之前通过postProcessMergedBeanDefinition方法找到的注入点,在这一步进行注入。完成属性注入后,就开始初始化了,初始化的流程在上篇文章中已经介绍过了,这里就不再赘述了。


总结


在这两篇文章中,我们已经对Bean的全部的生命周期做了详细分析,当然,对于一些复杂的代码,暂时还没有去深究,因为之后打算写一系列专门的源码分析文章。大家可以关注我后续的文章。对于整个Bean的生命周期可以总结画图如下

微信图片_20221112190124.png

首先,整个Bean的生命周期我们将其划分为两个部分

  1. 创建
  2. 销毁

对于创建阶段,我们又将其分为三步

  • 实例化
  • 属性注入
  • 初始化

我们可以看到,在整个过程中BeanPostPorcessor穿插执行,辅助Spring完成了整个Bean的生命周期。


相关文章
|
12天前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
1月前
|
XML Java 数据格式
Spring从入门到入土(bean的一些子标签及注解的使用)
本文详细介绍了Spring框架中Bean的创建和使用,包括使用XML配置文件中的标签和注解来创建和管理Bean,以及如何通过构造器、Setter方法和属性注入来配置Bean。
67 9
Spring从入门到入土(bean的一些子标签及注解的使用)
|
30天前
|
Java 测试技术 Windows
咦!Spring容器里为什么没有我需要的Bean?
【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
|
1月前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细解析Spring Bean的生命周期及其核心概念,并深入源码分析。Spring Bean是Spring框架的核心,由容器管理其生命周期。从实例化到销毁,共经历十个阶段,包括属性赋值、接口回调、初始化及销毁等。通过剖析`BeanFactory`、`ApplicationContext`等关键接口与类,帮助你深入了解Spring Bean的管理机制。希望本文能助你更好地掌握Spring Bean生命周期。
73 1
|
1月前
|
Java Spring
获取spring工厂中bean对象的两种方式
获取spring工厂中bean对象的两种方式
38 1
|
1月前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细介绍了Spring框架中的核心概念——Spring Bean的生命周期,包括实例化、属性赋值、接口回调、初始化、使用及销毁等10个阶段,并深入剖析了相关源码,如`BeanFactory`、`DefaultListableBeanFactory`和`BeanPostProcessor`等关键类与接口。通过理解这些核心组件,读者可以更好地掌握Spring Bean的管理和控制机制。
84 1
|
5月前
|
Java 开发者 Spring
解析Spring中Bean的生命周期
解析Spring中Bean的生命周期
55 2
|
5月前
|
XML druid Java
Spring5系列学习文章分享---第二篇(IOC的bean管理factory+Bean作用域与生命周期+自动装配+基于注解管理+外部属性管理之druid)
Spring5系列学习文章分享---第二篇(IOC的bean管理factory+Bean作用域与生命周期+自动装配+基于注解管理+外部属性管理之druid)
62 0
|
4月前
|
Java Spring 容器
Spring Boot 启动源码解析结合Spring Bean生命周期分析
Spring Boot 启动源码解析结合Spring Bean生命周期分析
103 11
|
3月前
|
前端开发 Java 开发者