除了使用阶段外,Spring 将 bean 的生命周期定义为实例化、属性填充、初始化和销毁四个阶段,并为每个阶段提供了多个拓展点用于自定义 bean 的创建过程。这篇文章介绍了 bean 的生命周期和其各个拓展点,通过图示生动的展示、并结合一个实例来演示全过程。
Spring 生命周期
graph LRClassLoad(类加载) –> Instantiation[实例化]Instantiation –> Populate[属性填充]Populate –> Initialization[初始化]Initialization –> Using(使用)Using –> Destruction[销毁]
上图中,每个箭头上都有 Spring 提供的拓展点。类加载不是 bean 生命周期的一部分,保留在图上纯粹是因为要提供第一个右向的箭头,而使用阶段也不在讨论范围内,故这两个采用圆角矩形。
拓展点的类型
Spring 提供的拓展点可以分为:
-
用于单个 bean 感知自身过程的专用拓展点:下方出现的、以 Aware 结尾为名的接口,
org.springframework.beans.factory.InitializingBean
接口和
org.springframework.beans.factory.DisposableBean
接口,这些接口都只定义了一个函数。bean 通过实现这些接口、重写其中的函数来实现拓展点。Spring 容器会在适当的时候调用这些函数。
-
用于所有普通 bean 初始化的通用拓展点:位于
org.springframework.beans.factory.config
包的
BeanPostProcessor
、
InstantiationAwareBeanPostProcessor
和
DestructionAwareBeanPostProcessor
接口,这些接口中定义了多个拓展点,使用时需要定义一个专门的类实现接口、重写必要的函数。Spring 容器会将这些实现类优先注册为 bean,待它们初始化完成后再初始化普通的 bean,在每个普通 bean 注册时,Spring 容器都会尝试调用所有已注册的通用拓展点。
classDiagramBeanPostProcessor <|– InstantiationAwareBeanPostProcessorBeanPostProcessor <|– DestructionAwareBeanPostProcessorBeanPostProcessor: +postProcessBeforeInitialization()BeanPostProcessor: +postProcessAfterInitialization()InstantiationAwareBeanPostProcessor: +postProcessBeforeInstantiation()InstantiationAwareBeanPostProcessor: +postProcessAfterInstantiation()DestructionAwareBeanPostProcessor: +postProcessBeforeDestruction()
1. 实例化
创建 bean 对象实例的过程,包括使用工厂模式创建和调用构造函数。Spring 通过
InstantiationAwareBeanPostProcessor
接口在实例化前和后各提供了两个通用拓展点,加上对象实例化的过程,执行顺序如下:
-
postProcessBeforeInstantiation
:在普通 bean 对象实例化开始之前调用
- 对象实例化
-
postProcessAfterInstantiation
:在普通 bean 对象实例化完成之后调用
2. 属性填充
如果对象中有 setter 函数,并通过配置元数据指定了注入的属性,Spring 容器会在这一步为其注入配置的值。完成属性填充后,Spring 通过 Aware(意为感知) 接口提供了十个专用拓展点,这些拓展点用于在 bean 自身内部、感知一些外部信息使用。调用顺序如下(下面提到的多个 Aware 接口中,前三个在
org.springframework.beans.factory
包中,4 ~ 9 在
org.springframework.context
包中,最后一个在
org.springframework.web.context
包中 ):
-
BeanNameAware#setBeanName
-
BeanClassLoaderAware#setBeanClassLoader
-
BeanFactoryAware#setBeanFactory
-
EnvironmentAware#setEnvironment
-
EmbeddedValueResolverAware#setEmbeddedValueResolver
-
ResourceLoaderAware#setResourceLoader
(仅在 ApplicationContext 中有效)
-
ApplicationEventPublisherAware#setApplicationEventPublisher
(仅在 ApplicationContext 中有效)
-
MessageSourceAware#setMessageSource
(仅在 ApplicationContext 中有效)
-
ApplicationContextAware#setApplicatioad8nContext
(仅在 ApplicationContext 中有效)
- 如果是 Web 应用程序,还有
ServletContextAware#setServletContext
(仅在 WebApplicationContext 中有效)
Aware 拓展点结束之后,还有一个用于在初始化之前、进行属性校验的
InitializingBean#afterPropertiesSet
专用拓展点。
3. 初始化
初始化是指通过 bean 在将要工作前进行的最后准备工作,通常是
@Bean
的
initMethod
属性定义的函数执行的过程 。Spring 通过
BeanPostProcessor
接口在初始化之前和之后提供了两个通用拓展点,加上初始化函数执行顺序为:
-
postProcessBeforeInitialization
- 自定义的初始化函数
-
postProcessAfterInitialization
4. 销毁
销毁是指 bean 释放其占用的一些外部资源的过程,通常是
@Bean
注解的
destroyMethod
属性定义的销毁函数执行的过程。Spring 通过
DestructionAwareBeanPostProcessor#postProcessBeforeDestruction
的通用拓展点,再加上
DisposableBean#destroy
提供了的专用拓展点,三者执行顺序为:
-
DestructionAwareBeanPostProcessor#postProcessBeforeDestruction
-
DisposableBean#destroy
- 自定义的销毁函数。
实例演示
一个简单的演示,实现了上文提到的 bean 生命周期全部的拓展点,通过日志打印的方式观察执行顺序来直观的感受。
在一个 bean 中实现全部的专用拓展点
SimpleBean 类
/*** 一个简单的 bean 实例,实现了 Spring 提供的 bean 生命周期全拓展点,内部函数实现顺序即为 bean 生命周期中各个函数的调用顺序*/@Slf4j(topic = \"简单Bean\")public class SimpleBeanimplements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware,EnvironmentAware, EmbeddedValueResolverAware, ResourceLoaderAware,ApplicationEventPublisherAware, MessageSourceAware, ApplicationContextAware, InitializingBean, DisposableBean {private EmptyBean emptyBean;static {//类加载期间 logger 还没有初始化,使用标准输出System.out.printf(\"[%s] 简单Bean : SimpleBean 类加载 loaded%n\", Thread.currentThread().getName());}public SimpleBean() {log.info(\"构造函数执行,创建实例\");}@Autowiredpublic void setEmptyBean(EmptyBean emptyBean) {56cthis.emptyBean = emptyBean;log.info(\"setter 函数执行,装配了 {}\", this.emptyBean);}/** 用于通知 bean 感知自身名称 */@Overridepublic void setBeanName(String name) {log.info(\"bean 名称为 {}\", name);}/** 用于通知 bean 感知加载自身的类加载器 */@Overridepublic void setBeanClassLoader(ClassLoader classLoader) {log.info(\"类加载器是 {}\", classLoader);}/** 用于通知 bean 感知创建自身的 bean 工厂 */@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {//BeanFactory 可能会重写 toString(),造成日志输出过多不便于查阅log.info(\"由 {}@{} 创建\", beanFactory.getClass(), beanFactory.hashCode());}/** 设置该 bean 的运行环境信息 */@Overridepublic void setEnvironment(Environment environment) {//environment.toString() 会将所有环境信息输出,造成日志输出过多不便于查阅log.info(\"运行的 JVM 型号是 {}\", environment.getProperty(\"java.vm.name\"));}/** 设置嵌入式配置解析器,可用于解析嵌入在应用程序包内的配置文件中的文本值 */@Overridepublic void setEmbeddedValueResolver(StringValueResolver resolver) {//在 application.properties 中定义了 editor.nad0ame 信息log.info(\"作者是 {}\", resolver.resolveStringValue(\"${editor.name}\"));}/** 设置用于资源解析的解析器,可用于解析任意格式的资源 */@Overridepublic void setResourceLoader(ResourceLoader resourceLoader) {log.info(\"资源解析器对象:{}\", resourceLoader);}/** 设置事件发布器,与 Spring 提供的事件发布订阅机制有关 */@Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {log.info(\"事件发布器对象:{}\", applicationEventPublisher);}/** 设置消息原,可用于实现国际化 */@Overridepublic void setMessageSource(MessageSource messageSource) {log.info(\"消息源对象:{}\", messageSource);}/** 为当前 bean 传入 ApplicationContext 引用,可使用该容器引用获取其他 bean 的引用 */@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {log.info(\"应用程序上下文对象:{}\", applicationContext.getDisplayName());}/** 在所有属性设置和 Aware 接口定义的行为都执行完成后,由 BeanFactory 调用,bean 可在此校验自身配置并最终初始化 */@Overridepublic void afterPropertiesSet() {log.info(\"属性装配全部完成,校验无误,开始初始化\");}/** 自定义的初始化方法 */public void initMethod() {log.info(\"自定义的初始化方法\");}/** 容器销毁时调用 */@Overridepublic void destroy() {log.info(\"容器即将关闭,销毁其中的 bean\");}/** 自定义的销毁方法 */public void destroyMethod() {log.info(\"自定义的销毁方法\");}}
/** 一个空的 bean,用于在 SimpleBean 中进行 setter 注入 */@Componentpublic class EmptyBean {}
自定义三种类型的通用拓展点
实例化处理器
@Slf4j(topic = \"自定义实例化处理器\")@Componentpublic class CustomInstantiationProcessor implements InstantiationAwareBeanPostProcessor {public CustomInstantiationProcessor() {log.info(\"InstantiationAwareBeanPostProcessor 在其他 bean 创建前就创建完成\");}/** 其他 bean 实例化之前调用 */@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {if (beanClass.equals(SimpleBean.class)) {log.info(\"{} 即将实例化\", beanName);1c1d}return null;}/** 其他 bean 实例化之后调用 */@Overridepublic boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {if (bean instanceof SimpleBean) {log.info(\"{} 实例化完成\", beanName);}return true;}}
初始化处理器
@Slf4j(topic = \"自定义初始化处理器\")@Componentpublic class CustomInitializationProcessor implements BeanPostProcessor {public CustomInitializationProcessor() {log.info(\"BeanPostProcessor 在其他 bean 创建前就创建完成\");}/** 其他 bean 初始化之前调用 */@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof SimpleBean) {log.info(\"{} 即将初始化\", beanName);}return bean;}/** 其他 bean 初始化完成之后调用 */@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof SimpleBean) {log.info(\"{} 初始化完成\", beanName);}return bean;}}
销毁处理器
@Slf4j(topic = \"自定义销毁处理器\")@Componentpublic class CustomDestructionProcessor implements DestructionAwareBeanPostProcessor {public CustomDestructionProcessor() {log.info(\"DestructionAwareBeanPostProcessor 在其他 bean 创建前就创建完成\");}/** 其他 bean 销毁之前调用 */@Overridepublic void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {if (bean instanceof SimpleBean) {log.info(\"{} 即将销毁\", beanName);}}}
入口类
@Slf4j@SpringBootApplicationpublic class DemoApplication implements CommandLineRunner {private SimpleBean bean;@Bean(initMethod = \"initMethod\", destroyMethod = \"destroyMethod\")public SimpleBean simpleBean() {return new SimpleBean();}@Autowiredpublic void setBean(SimpleBean bean) {this.bean = bean;}public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}@Overridepublic void run(String... args) {log.info(\"{} 使用\", bean.toString());}}
结果解析
- JSR 250 定义的 @PostConstruct、 @PreDestory 和 @Component 共同使用定义 bean 时,自定义的初始化函数会在
InitializingBean#afterPropertiesSet
,拓展点之前执行,后续查阅源码研究。