Skip to main content

Bean的生命周期?

作者:程序员马丁

在线博客:https://open8gu.com

note

大话面试,技术同学面试必备的八股文小册,以精彩回答应对深度问题,助力你在面试中拿个offer。

面试话术

总的来说,如果不考虑 BeanDefinition,那么 Bean 的生命周期可以分为四个阶段

实例化阶段

Spring 将会先推断 Bean 的类型,然后根据情况下选择通过 Supplier 接口、工厂方法或者构造器三种方式中的一种创建一个实例。此外,构造器注入也发生在这个阶段。

依赖注入阶段

  1. 设置一级缓存:在一级缓存中设置 ObjectFactory ,以便在循环依赖时正确进行代理;
  2. 解析依赖注入元数据:使用 MergedBeanDefinitionPostProcessor 后处理器对 Bean 中的注解属性和方法进行处理,从而解析并缓存自动装配所需要的元数据;
  3. 执行依赖注入:先根据名称或类型完成那些非注解式的依赖注入,然后再使用 InstantiationAwareBeanPostProcessor 后处理器根据上一步缓存的元数据对 Bean 按注解配置进行依赖注入。

初始化阶段

  1. 触发基础 Aware 接口:包括 BeanFactoryAwareClassLoaderAwareBeanNameAware 这 3 个 Aware 接口;
  2. 执行 BeanPostProcessor 前置处理,并且通过后处理器额外做了下面这几件事:
    • 执行注解方法:包括被 @PostConstruct@PreDestory 注解的方法。
    • 执行容器级 Aware 接口: 包括ApplicationContextAwareMessageSourceAwareApplicationEventPublisherAwareResourceLoaderAwareEmbeddedValueResolverAwareEnvironmentAware 这 6 个 Aware 接口。
    • 调用初始化方法:包括 InitializingBean 接口与在 XML 文件或 @Bean 注解中指定的自定义初始化方法。
  3. 执行 BeanPostProcessor 后置处理:这一步最重要的是创建了代理对象。

销毁阶段

这一步实际上是通过将 Bean 包装为 DisposableBeanAdapter 完成的,调用他的 destory 方法将会依次完成下述步骤:

  1. 调用后处理器:即调用 DestructionAwareBeanPostProcessor 后处理器的方法;
  2. DisposableBean 接口:即调用 DisposableBean 接口的 destory 方法(如果 Bean 实现了该接口);
  3. 自定义销毁方法:即用户指定的销毁时回调方法,比如在 XML 中配置的 destory-method,或者在 @Bean 配置的 destoryMethod

问题详解

Spring 中 Bean 生命的起点是 AbstractAutowireCapableBeanFactory.doCreateBean 方法,在这个方法中,我们可以总览 Bean 从无到有的整体流程:

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {

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


// 合并 BeanDefinition,获取目标类型父类的元数据
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}

// 在三级缓存中设置早期引用的 ObjectFactory,用于处理循环依赖
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
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");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

// =============== 依赖注入 & 初始化 ===============
Object exposedObject = bean;
try {
// 对 Bean 进行依赖注入
populateBean(beanName, mbd, instanceWrapper);
// 初始化 Bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}

// ... ...

// =============== 注册 bean 销毁回调 ===============
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}

return exposedObject;
}

在这个方法中,我们可以大体知道 Bean 创建流程分为四个主要阶段:

  • 实例化:通过各种方式最终创建一个 Bean 实例。
  • 依赖注入:对 Bean 完成依赖注入。
  • 初始化:对依赖注入完毕的 Bean 进行初始化,各种生命周期回调接口在这个阶段调用。
  • 注册销毁回调:如果 Bean 在销毁时需要进行后处理,或者本身实现了销毁阶段的回调接口,则此时需要注册该 Bean。

接下来,我们按这个划分方式,介绍 Bean 在各个阶段的处理,

1. 实例化阶段

这个阶段的主要逻辑都在 AbstractAutowireCapableBeanFactory.createBeanInstance 方法中完成:

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName);

if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}

// 尝试通过 BeanDefinition 定义的 supplier 函数创建 Bean
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}

// 尝试通过工厂方法创建 Bean
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}

// ... ...

// 通过 SmartInstantiationAwareBeanPostProcessor 获取用于实例化的构造器
// 如果有必要的话,在这个阶段进行构造器注入
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}

// 只有无参构造器,那就正常的实例化
return instantiateBean(beanName, mbd);
}

简单的来说,在这个阶段,Spring 先确认 Bean 的实际类型,然后再通过下述方式尝试实例化一个 Bean:

  • 如果 BeanDefinition 指定了 Supplier 函数式接口,则直接调用其创建。
  • 如果有有参构造器,那么就挑选出一个最合适的(通常就是参数最多的那个),然后调用构造器创建实例,并且一并完成构造器注入。
  • 如果只有无参构造器,那就正常的创建。

另外,这个方法最终返回的是 BeanWrapper 包装对象而不是实例本身,这个包装类将在后续依赖注入过程中,为设置属性或获取元数据之类的操作操作提供支持。

注:Supplier 接口一般是直接通过 BeanDefinition 指定的,相比起牵扯到依赖注入的构造器和工厂方法这两种创建方式,通过 Supplier 接口创建 Bean 最大的特点就是允许将创建 Bean 的过程完全的与 Spring 容器剥离。不过,除非是造轮子,否则正常情况下你基本不会用到它。

2. 依赖注入阶段

2.1. 前置处理

populateBean 执行前,有两个重要前置步骤:

  • 预处理 BeanDefinition:合并目标 Bean 父类的 BeanDefinition,获取 MergedBeanDefinition
  • 设置三级缓存:在三级缓存中设置早期引用的 ObjectFactory,用于处理循环依赖。

其中,第一点是依赖注入的关键步骤。在这一步,用上了一个较少见但是很重要的后处理器 MergedBeanDefinitionPostProcessor,它用于在属性注入之前对 BeanDefinition 中一些配置进行预处理。

它有两个至关重要的实现类:

  • AutowiredAnnotationBeanPostProcessor:实现基于 @Autowired@Value 注解的依赖注入。
  • CommonAnnotationBeanPostProcessor:实现基于 JSR250 规范(@Resouce) 与 JSR305 规范(@Inject@Named)注解的依赖注入。

在 postProcessMergedBeanDefinition 方法调用后,这两个后处理器将会扫描目标类中带有指定注解的属性与方法,并为其创建 InjectionMetadata 缓存

关于早期引用和循环依赖,请参见 Spring 如何解决循环依赖?✅ 什么是三级缓存?为什么需要?

2.2. 依赖注入

MergedBeanDefinitionPostProcessor 调用完毕后,就会调用 AbstractAutowireCapableBeanFactory.populateBean 方法真正的完成依赖注入:

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// ... ...

PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

// 根据名称或类型进行依赖注入
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
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;
}

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;
}
}
= pvsToUse;
}
}
}


// ... ...
}

在依赖注入阶段,不同的注入点又根据配置方式分为两类:

2.2.1. 不基于注解注入

有些依赖注入是不基于注解实现的 —— 比如传统 XML 配置,或者你直接在 BeanDefinition 里面指定了依赖注入项 —— 那么这部分属性会直接通过 BeanDefinition 中的 PropertyValues 组件按类型或者名称注解注入

对应到源码中,就是 autowireByNameautowireByType 这一段。

2.2.2. 基于注解注入

如果是基于注解注入,比如 @Resource 或者 @Autowired,那么这部分属性会通过 InstantiationAwareBeanPostProcessor 后处理器的 postProcessProperties 方法完成注入。

常用的几种依赖注入后处理器(比如 AutowiredAnnotationBeanPostProcessor 或者 CommonAnnotationBeanPostProcessor),它们都同时实现了 MergedBeanDefinitionPostProcessorInstantiationAwareBeanPostProcessor 两个接口。

这意味着:

  • 在执行 MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition 方法时,它们会预先解析好类中带有指定注解的属性或方法,为其构建并缓存 InjectionMetadata
  • 在执行 InstantiationAwareBeanPostProcessor.postProcessProperties方法的时候,它们就会根据预算解析并缓存的 InjectionMetadata 完成依赖注入。

顺带一提,AutowireCapableBeanFactory 接口提供的 autowireBeanautowireBeanProperties 等方法也是基于 populateBean 方法实现的。它们的具体用法可以参见:✅ 不被 Spring 管理的对象也能进行依赖注入吗?

3. 初始化阶段

完成了属性注入后,接下来就是 Bean 的初始化。在这个阶段,Spring 将使用后处理器 BeanPostProcessor完成对 Bean 的处理,并且为其调用各种回调接口。我们熟悉的各种回调接口和注解有八成都是在这个阶段触发的。

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
// 调用一部分容器级 Aware 回调方法
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}

// 触发 BeanPostProcessors 的 postProcessBeforeInitialization 方法
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

try {
// 触发 init-method
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}

// 触发 BeanPostProcessors 的 postProcessAfterInitialization 方法
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

return wrappedBean;
}

由于在这个阶段调用的回调接口和处理的注解较多,因此接下来我们将按执行顺序与触发点依次对其分组介绍。

3.1. 调用基础 Aware 接口

在初始化的最开始,Spring 将会通过 invokeAwareMethods调用最基础的三个 Aware 接口:

  • BeanNameAware:获取 beanName。
  • ClassLoaderAware:获取类加载器。
  • BeanFactoryAware:获取管理它的 BeanFactory
private void invokeAwareMethods(String beanName, Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}

值得一提的是,SpringBoot 中有一些组件似乎也支持类似的 Aware 接口,不过实际上它们并不是在 BeanFactory 中进行调用的。

比如 AutoConfigurationImportListenerAutoConfigurationImportFilter 这两个,就是直接在自动配置导入选择器 AutoConfigurationImportSelector 中完成调用。具体可以参见:✅ 什么是自动装配?

3.2. 执行 BeanPostProcessor 前置处理

接着,Spring 会通过 applyBeanPostProcessorsBeforeInitialization 调用 BeanPostProcessorpostProcessBeforeInitialization 方法完成前置处理:

@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {

Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}

注意,在这个阶段,很多的 Aware 接口与通用注解实际上是通过 BeanPostProcessor 进行触发的:

3.2.1. 执行注解方法

Spring 通过 InitDestroyAnnotationBeanPostProcessor 这个后处理器来触发带有特定生命周期注解的方法。比如以下几个注解就是通过它触发执行的:

  • @PostConstruct
  • @PreDestory
  • @Init
  • @Destory

也就是说,实际上 @PostConstruct 与 @Init 注解的方法要比默认的初始化方法(init-method)更早执行。

3.2.2. 执行容器级 Aware 接口

接着,通过 ApplicationContextAwareProcessor,Spring 会触发下述 6 个容器级 Aware 接口中的方法:

  • EnvironmentAware:用于获取环境变量,一般用于获取应用的配置。
  • EmbeddedValueResolverAware:用于获取字符串解析器,@Value 里面的表达式实际上就是基于该接口返回的 StringValueResolver 解析的,这个在造轮子的时候尤其有用。
  • ResourceLoaderAware:获取资源加载器。
  • ApplicationEventPublisherAware:获取 Spring 事件推送者,一般就是 ApplicationContext 本身。
  • MessageSourceAware:获取消息源,一般用来实现国际化相关的功能。
  • ApplicationContextAware:获取当前 Bean 所在的 ApplicationContext
3.2.3. 执行 ImportAware

其实,这里还有一个用的比较少的 Aware 接口被调用,那就是 ImportAware

调用它的处理器 ImportAwareBeanPostProcessor 实际上是 ConfigurationClassPostProcessor 的一个内部类,它会在后处理 BeanFactory 的时候默认注册到当前的 BeanFactory 中。

ImportAware 一般用于配合 @Import 注解使用,通过 @Import 注解导入的组件如果实现了 ImportAware 接口,就可以拿到 @Import 注解所在类的元数据(也就是注解本身)。

这个接口平时用的比较少,因此简单了解即可。

关于 @Import 注解与 ImportAware,请参见:@Import 注解是怎么生效的?

3.3. 调用初始化方法

完成 BeanPostProcessor 的前置处理后,Spring 将会调用初始化方法,它包含两方面:

  • InitializingBean:如果 Bean 实现了 InitializingBean 接口,那么此时会调用接口的 afterPropertiesSet
  • init-method:即用户自定义的初始化方法。简单的来说,就是 XML 文件中配置 Bean 时 init-method 选项指定的方法,或者 @Bean 注解的 initMethod 属性指定的方法。

3.4. 执行 BeanPostProcessor 后置处理

接着,Spring 会通过 applyBeanPostProcessorsAfterInitialization 调用 BeanPostProcessorpostProcessAfterInitialization 方法完成前置处理:

@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {

Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}

在这个步骤,不过我们需要注意的是 AbstractAutoProxyCreator 这个后处理器,它实际上就是 SpringAOP 用于自动创建代理的组件。

在不因为循环依赖导致提前创建代理对象的情况下,Spring 在这一步 —— 也就是整个初始化过程的最后 —— 创建代理对象。

关于 AbstractAutoProxyCreator ,请参见:✅ SpringAOP 有哪些核心组件?

4. 销毁阶段

Spring 中 Bean 的销毁过程比较有意思,因为 Spring 表面上提供了两套销毁回调机制:

  • DestructionAwareBeanPostProcessor:可以感知 Bean 销毁的后处理器。
  • Bean 销毁时的回调方法:包括 DisposableBean 接口与自定义的 destory-method

然而,实际上,在 doCreateBean 的最后面,当 Bean 完成所有处理后,仅当 Bean 本身是单例的时候, Spring 会为其创建并注册一个 DisposableBeanAdapter

protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
if (mbd.isSingleton()) {
// Register a DisposableBean implementation that performs all destruction
// work for the given bean: DestructionAwareBeanPostProcessors,
// DisposableBean interface, custom destroy method.
registerDisposableBean(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
else {
// A bean with a custom scope...
Scope scope = this.scopes.get(mbd.getScope());
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
}
scope.registerDestructionCallback(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
}
}

DisposableBeanAdapter本身实现了 DisposableBean 接口,它代理了 Bean ,并且在内部持有支持对 Bean 进行处理的 DestructionAwareBeanPostProcessor 后处理。

当执行销毁的时候,Spring 将获取对应的 DisposableBeanAdapter 缓存,然后调用它的 destory 方法,此时,DisposableBeanAdapter 将依次调用:

  • 后处理器DestructionAwareBeanPostProcessor 后处理器的方法。
  • DisposableBean 接口DisposableBean 接口的 destory 方法(如果 Bean 实现了这个接口)。
  • 自定义销毁方法:用户指定的销毁时回调方法,也就是在 XML 中配置的 destory-method 或者 @Bean 中通过 destoryMethod 属性配置的方法。