关于node.js:聊透Spring-bean的生命周期

7次阅读

共计 8699 个字符,预计需要花费 22 分钟才能阅读完成。

在对于 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 推断创立形式还是比拟聪慧的,具体逻辑是:

先判断是否提供了 Supplier,如果提供,则通过 Supplier 产生对象。
再判断是否提供工厂办法,如果提供,则应用工厂办法产生对象。
如果都没提供,须要进行构造方法的推断,逻辑为:

如果仅有一个构造方法,会间接应用该构造方法 (如果构造方法有参数,会主动注入依赖参数)
如果有多个结构参数,会判断有没有加了 @Autowired 注解的结构参数:

如果没有,Spring 默认抉择无参构造方法;
如果有,且有 @Autowired(required=true)的构造方法,就会抉择该构造方法;
如果有,然而没有 @Autowired(required=true)的构造方法,Spring 会从所有加了 @Autowired 的构造方法中,依据结构器参数个数、类型匹配水平等综合打分,抉择一个匹配参数最多,类型最精确的构造方法。

 对于创立 bean 时,具体如何抉择构造方法的,本文咱们不具体开展。因为本文宗旨在于剖析 bean 的生命周期,咱们只须要简略晓得 Spring 会抉择一个构造方法,而后通过反射创立出对象即可。其实在浏览 Spring 源码的时候,小伙伴们也肯定要学会抓大放小,重点关注外围流程,细枝末节的中央能够先战术性疏忽,后续有须要时再回过头剖析也不迟,千万不要陷进去,迷失了方向。

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

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);
  }

}
}
复制代码

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 循环依赖的解决之道,对本阶段的内容也有具体的叙述。

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 依赖注入 中有详细分析,不分明的小伙伴能够先去感受一下 Spring 依赖注入的微妙之处。

1.5 初始化 bean
 该阶段次要做 bean 的初始化操作,包含:回调 Aware 接口、回调初始化办法、生成代理对象等。

invokeAwareMethods():回调 BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 感知接口。
回调后置处理器的前置办法,其中:

ApplicationContextAwareProcessor: 回调 EnvironmentAware、ResourceLoaderAware、ApplicationContextAware、ApplicationEventPublisherAware、MessageSourceAware、EmbeddedValueResolverAware 感知接口。
InitDestroyAnnotationBeanPostProcessor:调用了标注了 @PostConstruct 的办法。

invokeInitMethods()调用初始化办法:

如果 bean 是 InitializingBean 的子类, 先调用 afterPropertiesSet()。
回调自定义的 initMethod,比方通过 @Bean(initMethod = “xxx”)指定的初始化办法。

回调后置处理器的后置办法,可能返回代理对象。其中 AbstractAutoProxyCreator 和 AbstractAdvisingBeanPostProcessor 都有可能产生代理对象,比方 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;
}
复制代码

 在初始化实现后,bean 会被放到单例池中,正式开始本人的使命:为我的项目服务,比方接管 http 申请,进行 CRUD 等等。后续有应用到该 bean 的中央,也是间接从单例池中获取,不会再次创立 bean(仅单例的哦)。

  1. 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 的创立了。

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

2.2 实例化后回调
 在后面的章节咱们剖析过:在容器中的 bean 实例化,放到单例池中之后,bean 在创立阶段的生命周期就正式实现,进入应用中阶段,开启对完服务之路。的确,这就是创立 bean 的全过程,如果有小伙伴看过笔者之前的聊 Spring 事件的那篇文章(聊透 Spring 事件机制),会发现对于 @EventListener 处理器的辨认注册,是在 afterSingletonsInstantiated 阶段实现的。其实这里也是一个拓展点,咱们齐全能够实现 SmartInitializingSingleton#afterSingletonsInstantiated(),在 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 是 DisposableBean、AutoCloseable 的子类,或者有 destroy-method 等,会注册为可销毁的 bean,在容器敞开时,调用对应的办法进行 bean 的销毁。

正文完
 0