Bean的生命周期?
作者:程序员马丁
在线博客:https://open8gu.com
大话面试,技术同学面试必备的八股文小册,以精彩回答应对深度问题,助力你在面试中拿个offer。
面试话术
总的来说,如果不考虑 BeanDefinition,那么 Bean 的生命周期可以分为四个阶段:
实例化阶段
Spring 将会先推断 Bean 的类型,然后根据情况下选择通过 Supplier 接口、工厂方法或者构造器三种方式中的一种创建一个实例。此外,构造器注入也发生在这个阶段。
依赖注入阶段
- 设置一级缓存:在一级缓存中设置
ObjectFactory
,以便在循环依赖时正确进行代理; - 解析依赖注入元数据:使用
MergedBeanDefinitionPostProcessor
后处理器对 Bean 中的注解属性和方法进行处理,从而解析并缓存自动装配所需要的元数据; - 执行依赖注入:先根据名称或类型完成那些非注解式的依赖注入,然后再使用
InstantiationAwareBeanPostProcessor
后处理器根据上一步缓存的元数据对 Bean 按注解配置进行依赖注入。
初始化阶段
- 触发基础 Aware 接口:包括
BeanFactoryAware
、ClassLoaderAware
与BeanNameAware
这 3 个Aware
接口; - 执行 BeanPostProcessor 前置处理,并且通过后处理器额外做了下面这几件事:
- 执行注解方法:包括被
@PostConstruct
和@PreDestory
注解的方法。 - 执行容器级 Aware 接口: 包括
ApplicationContextAware
、MessageSourceAware
、ApplicationEventPublisherAware
、ResourceLoaderAware
、EmbeddedValueResolverAware
与EnvironmentAware
这 6 个Aware
接口。 - 调用初始化方法:包括
InitializingBean
接口与在 XML 文件或@Bean
注解中指定的自定义初始化方法。
- 执行注解方法:包括被
- 执行 BeanPostProcessor 后置处理:这一步最重要的是创建了代理对象。
销毁阶段
这一步实际上是通过将 Bean 包装为 DisposableBeanAdapter
完成的,调用他的 destory
方法将会依次完成下述步骤:
- 调用后处理器:即调用
DestructionAwareBeanPostProcessor
后处理器的方法; - DisposableBean 接口:即调用
DisposableBean
接口的destory
方法(如果 Bean 实现了该接口); - 自定义销毁方法:即用户指定的销毁时回调方法,比如在 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 组件按类型或者名称注解注入。
对应到源码中,就是 autowireByName
和 autowireByType
这一段。
2.2.2. 基于注解注入
如果是基于注解注入,比如 @Resource
或者 @Autowired
,那么这部分属性会通过 InstantiationAwareBeanPostProcessor 后处理器的 postProcessProperties 方法完成注入。
常用的几种依赖注入后处理器(比如 AutowiredAnnotationBeanPostProcessor
或者 CommonAnnotationBeanPostProcessor
),它们都同时实现了 MergedBeanDefinitionPostProcessor
与 InstantiationAwareBeanPostProcessor
两个接口。
这意味着:
- 在执行
MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition
方法时,它们会预先解析好类中带有指定注解的属性或方法,为其构建并缓存InjectionMetadata
。 - 在执行
InstantiationAwareBeanPostProcessor.postProcessProperties
方法的时候,它们就会根据预算解析并缓存的InjectionMetadata
完成依赖注入。
顺带一提,
AutowireCapableBeanFactory
接口提供的autowireBean
、autowireBeanProperties
等方法也是基于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 中进行调用的。
比如 AutoConfigurationImportListener
与 AutoConfigurationImportFilter
这两个,就是直接在自动配置导入选择器 AutoConfigurationImportSelector
中完成调用。具体可以参见:✅ 什么是自动装配?
3.2. 执行 BeanPostProcessor 前置处理
接着,Spring 会通过 applyBeanPostProcessorsBeforeInitialization
调用 BeanPostProcessor
的 postProcessBeforeInitialization
方法完成前置处理:
@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
调用 BeanPostProcessor
的 postProcessAfterInitialization
方法完成前置处理:
@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
属性配置的方法。