在关于Spring的一切解读中,Bean的生命周期都可谓是重中之重,甚至还有人称Spring便是个办理Bean的容器。Bean的生命周期之所以这么重要,被重复提及,是由于Spring的中心才干,比方目标创立(IOC)特点注入(DI)初始化办法的调用署理目标的生成(AOP)等功能的完结,都是在bean的生命周期中完结的。清楚了bean的生命周期,咱们才干知道Spring的奇特魔法终究是什么,是怎样一步步赋能,让原本一般的java目标,最终变成拥有超才干的bean的。

1. bean的生命周期

 Spring的生命周期大致分为:创立 -> 特点填充 -> 初始化bean -> 运用 -> 毁掉 几个中心阶段。咱们先来简略了解一下这些阶段所做的工作:

  • 创立阶段主要是创立目标,这儿咱们看到,目标的创立权交由Spring办理了,不再是咱们手动new了,这也是IOC的概念。
  • 特点填充阶段主要是进行依靠的注入,将当时目标依靠的bean目标,从Spring容器中找出来,然后填充到对应的特点中去。
  • 初始化bean阶段做的工作相对比较复杂,包含回调各种Aware接口、回调各种初始化办法、生成AOP署理目标也在该阶段进行,该阶段主要是完结初始化回调,后边咱们慢慢剖析。
  • 运用bean阶段,主要是bean创立完结,在程序运转期间,供给服务的阶段。
  • 毁掉bean阶段,主要是容器封闭或停止服务,对bean进行毁掉处理。

 当然,bean的生命周期中还包含其他的流程,比方露出工厂目标等,仅仅相对而言都是为其他功能做伏笔和预备的,再讲到对应功能时,咱们在做详细剖析。

1.1 创立bean

 目标的创立是bean生命周期的第一步,毕竟要先有1才干有0嘛。创立目标的办法有许多,比方 new反射clone等等,Spring是怎样创立目标的呢?绝大多数状况下,Spring是经过反射来创立目标的,不过假如咱们供给了Supplier或许工厂办法,Spring也会直接运用咱们供给的创立办法。

 咱们从源码动身,看一下Spring是怎么挑选创立办法的:

// 源码坐落 AbstractAutowireCapableBeanFactory.java
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
   // 再次解析BeanDefinition的class,保证class现已被解析
   Class<?> beanClass = resolveBeanClass(mbd, beanName);
   // 1: 假如供给了Supplier,经过Supplier发生目标
   Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
   if (instanceSupplier != null) {
      return obtainFromSupplier(instanceSupplier, beanName);
   }
   // 2: 假如有工厂办法,运用工厂办法发生目标
   // 在@Configration装备@Bean的办法,也会被解析为FactoryMethod
   if (mbd.getFactoryMethodName() != null) {
      return instantiateUsingFactoryMethod(beanName, mbd, args);
   }
   //...省掉部分代码
   // 3: 揣度结构办法
   // 3.1 执行后置处理器,获取候选结构办法
   Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
   // 3.2 需求主动注入的状况
   if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
         mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
      return autowireConstructor(beanName, mbd, ctors, args);
   }
   // 3.3 默许运用没有参数的结构办法
   return instantiateBean(beanName, mbd);
}

 经过咱们跟踪源码,发现Spring揣度创立办法仍是比较聪明的,详细逻辑是:

  1. 先判别是否供给了Supplier,假如供给,则经过Supplier发生目标。
  2. 再判别是否供给工厂办法,假如供给,则运用工厂办法发生目标。
  3. 假如都没供给,需求进行结构办法的揣度,逻辑为:
    • 假如仅有一个结构办法,会直接运用该结构办法(假如结构办法有参数,会主动注入依靠参数)
    • 假如有多个结构参数,会判别有没有加了@Autowired注解的结构参数:
      • 假如没有,Spring默许挑选无参结构办法;
      • 假如有,且有@Autowired(required=true)的结构办法,就会挑选该结构办法;
      • 假如有,可是没有@Autowired(required=true)的结构办法,Spring会从一切加了@Autowired的结构办法中,依据结构器参数个数、类型匹配程度等综合打分,挑选一个匹配参数最多,类型最准确的结构办法。

聊透Spring bean的生命周期

 关于创立bean时,详细怎么挑选结构办法的,本文咱们不详细展开。由于本文宗旨在于剖析bean的生命周期,咱们只需求简略知道Spring会挑选一个结构办法,然后经过反射创立出目标即可。其实在阅览Spring源码的时分,小伙伴们也必定要学会抓大放小,要点重视中心流程,细枝末节的当地能够先战术性疏忽,后续有需求时再回过头剖析也不迟,千万不要陷进去,迷失了方向。

 这儿给感兴趣的小伙伴附上一张流程图,感兴趣的小伙伴也能够留言,后续咱们也能够独自剖析。

聊透Spring bean的生命周期

1.2 merged BeanDefinition

 本阶段是Spring供给的一个拓宽点,经过MergedBeanDefinitionPostProcessor类型的后置处理器,能够对bean对应的BeanDefinition进行修正。Spring本身也充分利用该拓宽点,做了许多初始化操作(并没有修正BeanDefinition),比方查找标注了@Autowired@Resource@PostConstruct@PreDestory 的特点和办法,便利后续进行特点注入和初始化回调。当然,咱们也能够自定义完结,用来修正BeanDefinition信息或许咱们需求的初始化操作,感兴趣的小伙伴能够自行试一下哦。

protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
   for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof MergedBeanDefinitionPostProcessor) {
         MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
         bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
      }
   }
}

聊透Spring bean的生命周期

聊透Spring bean的生命周期

1.3 露出工厂目标

 本阶段主要是将前期bean目标提早放入到三级缓存singletonFactories中,为循环依靠做支持。在后续进行特点填充时,假如发生循环依靠,能够从三级缓存中经过getObject()获取该bean,完结循环依靠场景下的主动注入。

boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
      isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
   if (logger.isTraceEnabled()) {
      logger.trace("Eagerly caching bean '" + beanName +
            "' to allow for resolving potential circular references");
   }
   // 做循环依靠的支持 将前期实例化bean的ObjectFactory,增加到单例工厂(三级缓存)中
   addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

 该阶段彻底是为了支撑循环依靠的,是Spring为处理循环依靠埋的伏笔,在Bean的生命周期中彻底能够疏忽。这儿为了完整性,和小伙伴们简略提及一下。

假如对Spring怎么处理循环依靠不是很清楚的话,能够看笔者的另一篇文章 聊透Spring循环依靠,详细剖析了Spring循环依靠的处理之道,对本阶段的内容也有详细的叙说。

聊透Spring bean的生命周期

1.4 特点填充

 本阶段完结了Spring的中心功能之一:依靠注入,包含主动注入@Autowired注入@Resource注入等。Spring会依据bean的注入模型(默许不主动注入),挑选依据名称主动注入仍是依据类型主动注入。然后调用InstantiationAwareBeanPostProcessor#postProcessProperties()完结@Autowired和@Resource的特点注入。

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
   // 省掉部分代码
   // 获取bean的注入类型
   int resolvedAutowireMode = mbd.getResolvedAutowireMode();
   // 1: 主动注入
   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) {
      if (pvs == null) {
         pvs = mbd.getPropertyValues();
      }
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            // 要点: 完结@Autowired @Resource特点填充
            PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
               if (filteredPds == null) {
                  // 需求注入的特点,会过滤掉Aware接口包含的特点(经过ignoreDependencyInterface增加)
                  filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
               }
               pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
               if (pvsToUse == null) {
                  return;
               }
            }
            pvs = pvsToUse;
         }
      }
   }
    // 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);
   }
}

聊透Spring bean的生命周期

聊透Spring bean的生命周期

关于依靠注入,笔者在 聊透Spring依靠注入 中有详细剖析,不清楚的小伙伴能够先去感受一下Spring依靠注入的美妙之处。

1.5 初始化bean

 该阶段主要做bean的初始化操作,包含:回调Aware接口回调初始化办法生成署理目标等。

  • invokeAwareMethods():回调BeanNameAware、BeanClassLoaderAware、BeanFactoryAware感知接口。
  • 回调后置处理器的前置办法,其中:
    • ApplicationContextAwareProcessor: 回调EnvironmentAware、ResourceLoaderAware、ApplicationContextAwareApplicationEventPublisherAware、MessageSourceAware、EmbeddedValueResolverAware感知接口。
    • InitDestroyAnnotationBeanPostProcessor:调用了标注了@PostConstruct的办法。
  • invokeInitMethods()调用初始化办法:
    • 假如bean是InitializingBean的子类, 先调用afterPropertiesSet()
    • 回调自定义的initMethod,比方经过@Bean(initMethod = “xxx”)指定的初始化办法。
  • 回调后置处理器的后置办法,可能回来署理目标。其中AbstractAutoProxyCreatorAbstractAdvisingBeanPostProcessor都有可能发生署理目标,比方InfrastructureAdvisorAutoProxyCreator完结了@Transactional署理目标的生成,AsyncAnnotationBeanPostProcessor完结了@Async署理目标的生成。
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
  // 1: 回调Aware接口中的办法
  // 完结Aware办法的回调(BeanNameAware,BeanClassLoaderAware,BeanFactoryAware)
  invokeAwareMethods(beanName, bean);
   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
      // 2: 调用before...办法
      // ApplicationContextAwareProcessor: 其他Aware办法的回调
      // InitDestroyAnnotationBeanPostProcessor: @PostConstruct办法的回调
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }
   try {
      // 3: 完结xml版别和@bean(initMethod)的init办法回调
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   // 4: 调用after办法
   // 要点: AOP生成署理目标
   if (mbd == null || !mbd.isSynthetic()) {
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }
   return wrappedBean;
}

聊透Spring bean的生命周期

 在初始化完结后,bean会被放到单例池中,正式开始自己的任务:为项目服务,比方接纳http请求,进行CRUD等等。后续有运用到该bean的当地,也是直接从单例池中获取,不会再次创立bean(仅单例的哦)。

2. bean的来龙去脉

2.1 bean的扫描阶段

 现在咱们现已知道Spring bean是怎么创立的了,那什么时分创立这些bean呢,是遵从懒加载的思维,在实际运用的时分在创立吗?其实不是的,由于bean之间的复杂关系和生命周期的原因,Spring在容器启动的时分,就会实例化这些bean,然后放到单例池中,即用即取。并且在创立前、创立中、创立后都会做许多检查,保证创立的bean是符合要求的,这些咱们就不赘述了。

 言归正传,细心的你必定发现,创立bean时主要是从RootBeanDefinition mbd这个参数获取bean的相关信息的,其实这便是大名鼎鼎的BeanDefinition,其中封装了关于bean的元数据信息,关于BeanDefinition,后续咱们会独自解说,这儿咱们先了解为bean的元数据信息即可。那么这些元数据信息是什么时分解析的呢?

 这就要说到Spring的类扫描了,其大致流程是:经过ASM字节码技术扫描一切的类 -> 找出需求Sp加了@Compont注解的(简略了解) -> 封装成BeanDefinition -> 存放到调集中。后续再实例化bean的时分,就能够遍历这个调集,获取到BeanDefinition,然后进行bean的创立了。

聊透Spring bean的生命周期

关于处理类扫描的ConfigurationClassPostProcessor后置处理器以及ConfigurationClassParserComponentScanAnnotationParser扫描器的详细细节,后续咱们独自解说,和本章节关系不大,咱们先简略了解即可。

2.2 实例化后回调

 在前面的章节咱们剖析过:在容器中的bean实例化,放到单例池中之后,bean在创立阶段的生命周期就正式完结,进入运用中阶段,敞开对完服务之路。的确,这便是创立bean的全过程,假如有小伙伴看过笔者之前的聊Spring事件的那篇文章(聊透Spring事件机制),会发现关于@EventListener处理器的辨认注册,是在afterSingletonsInstantiated阶段完结的。其实这儿也是一个拓宽点,咱们彻底能够完结SmartInitializingSingleton#afterSingletonsInstantiated(),在bean初始化完结后会回调该办法,进而触发咱们自己的事务逻辑,故这儿咱们独自说一下。不清楚的小伙伴请移步先去了解一下哦。

聊透Spring bean的生命周期

2.3 bean的毁掉阶段

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
   // ...省掉代码
   try {
      // 为bean注册DisposableBean,在容器封闭时,调用destory()
      registerDisposableBeanIfNecessary(beanName, bean, mbd);
   }
   catch (BeanDefinitionValidationException ex) {
      throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
   }
   return exposedObject;
}

 在创立bean的时分,会判别假如bean是DisposableBeanAutoCloseable的子类,或许有 destroy-method等,会注册为可毁掉的bean,在容器封闭时,调用对应的办法进行bean的毁掉。

聊透Spring bean的生命周期