Spring Bean生命周期13步:从实例化到销毁每一步都有代码佐证
Spring Bean生命周期13步:从实例化到销毁每一步都有代码佐证
适读人群:想彻底搞清楚Spring Bean初始化顺序、扩展点时机的Java开发者 | 阅读时长:约20分钟
开篇故事
面试里被问频率最高的 Spring 题目之一,就是"说说 Bean 的生命周期"。
很多人背得出几个关键词:@PostConstruct、InitializingBean、BeanPostProcessor……但说不清楚它们的执行顺序,更说不清楚为什么有这么多"重复"的初始化扩展点。
我之前带新人做源码导读,讲到 Bean 生命周期这里,直接上了一个完整的 Demo:把所有扩展点全部实现,在每个方法里打一行日志,然后启动,看输出顺序。这个方式比画流程图有效多了。
今天把这个 Demo 完整整理出来,每一步都有可运行的代码。
一、Bean 生命周期全貌
二、完整演示代码
2.1 Bean 本身实现所有扩展点
package com.laozhang.lifecycle;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* 完整演示 Spring Bean 生命周期的所有扩展点
* 启动后观察日志输出顺序
*/
@Slf4j
@Component
public class LifecycleDemoBean implements
BeanNameAware,
BeanClassLoaderAware,
BeanFactoryAware,
ApplicationContextAware,
InitializingBean,
DisposableBean {
private String name;
// ===== 步骤1:构造器 =====
public LifecycleDemoBean() {
log.info("【步骤1】构造器执行:实例化Bean");
}
// ===== 步骤2:属性注入 =====
// 由Spring自动完成,这里用一个setter来观察
public void setName(String name) {
log.info("【步骤2】属性注入:name = {}", name);
this.name = name;
}
// ===== 步骤3:BeanNameAware =====
@Override
public void setBeanName(String beanName) {
log.info("【步骤3】BeanNameAware.setBeanName:beanName = {}", beanName);
}
// ===== 步骤4:BeanClassLoaderAware =====
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
log.info("【步骤4】BeanClassLoaderAware.setBeanClassLoader:{}",
classLoader.getClass().getSimpleName());
}
// ===== 步骤5:BeanFactoryAware =====
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
log.info("【步骤5】BeanFactoryAware.setBeanFactory:{}",
beanFactory.getClass().getSimpleName());
}
// ===== 步骤6:ApplicationContextAware =====
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
log.info("【步骤6】ApplicationContextAware.setApplicationContext:{}",
applicationContext.getApplicationName());
}
// BeanPostProcessor.postProcessBeforeInitialization 在步骤7执行(在外部类里实现)
// ===== 步骤8:@PostConstruct =====
@PostConstruct
public void postConstruct() {
log.info("【步骤8】@PostConstruct:所有属性已注入,可以做初始化了");
}
// ===== 步骤9:InitializingBean =====
@Override
public void afterPropertiesSet() throws Exception {
log.info("【步骤9】InitializingBean.afterPropertiesSet:属性设置完毕");
}
// ===== 步骤10:自定义 init 方法(在@Bean注解里指定,或在配置文件里声明)=====
public void customInit() {
log.info("【步骤10】自定义init方法:customInit()");
}
// BeanPostProcessor.postProcessAfterInitialization 在步骤11执行
// ===== 步骤12:@PreDestroy =====
@PreDestroy
public void preDestroy() {
log.info("【步骤12】@PreDestroy:容器即将关闭,做资源释放准备");
}
// ===== 步骤13:DisposableBean =====
@Override
public void destroy() throws Exception {
log.info("【步骤13】DisposableBean.destroy:销毁Bean,释放资源");
}
}2.2 BeanPostProcessor 实现(步骤7和11)
package com.laozhang.lifecycle;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
/**
* BeanPostProcessor:对所有Bean生效
* 步骤7:postProcessBeforeInitialization(@PostConstruct之前)
* 步骤11:postProcessAfterInitialization(所有初始化完成后,AOP代理在这里创建)
*/
@Slf4j
@Component
public class LifecycleBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof LifecycleDemoBean) {
log.info("【步骤7】BeanPostProcessor.postProcessBeforeInitialization:beanName = {}",
beanName);
}
return bean; // 必须返回bean(或替换后的对象)
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof LifecycleDemoBean) {
log.info("【步骤11】BeanPostProcessor.postProcessAfterInitialization:beanName = {}",
beanName);
// AOP代理就在这里创建:AbstractAutoProxyCreator继承了BeanPostProcessor
// 在postProcessAfterInitialization里判断是否需要代理,并返回代理对象
}
return bean;
}
}2.3 配置类(触发步骤10)
package com.laozhang.lifecycle;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class LifecycleConfig {
/**
* 通过 @Bean 的 initMethod 指定自定义初始化方法
* 这是步骤10,在 InitializingBean.afterPropertiesSet() 之后执行
*/
@Bean(initMethod = "customInit", destroyMethod = "customDestroy")
public LifecycleDemoBean lifecycleDemoBean() {
LifecycleDemoBean bean = new LifecycleDemoBean();
bean.setName("老张的Bean");
return bean;
}
}2.4 InstantiationAwareBeanPostProcessor(更早的扩展点)
很多人不知道还有一个更早的扩展点 InstantiationAwareBeanPostProcessor,它在实例化之前就介入了:
package com.laozhang.lifecycle;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.stereotype.Component;
/**
* InstantiationAwareBeanPostProcessor:比 BeanPostProcessor 更早
*
* postProcessBeforeInstantiation:实例化之前(可以返回代理对象,直接跳过实例化)
* postProcessAfterInstantiation:实例化之后,属性注入之前
* postProcessProperties:属性注入前,可以修改PropertyValues
*/
@Slf4j
@Component
public class LifecycleInstantiationAwareBPP implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName)
throws BeansException {
if (beanClass == LifecycleDemoBean.class) {
log.info("【步骤0.5】postProcessBeforeInstantiation:实例化之前,可以返回代理直接跳过实例化");
}
return null; // 返回null表示让Spring正常实例化;返回非null则跳过构造器
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName)
throws BeansException {
if (bean instanceof LifecycleDemoBean) {
log.info("【步骤1.5】postProcessAfterInstantiation:实例化完成,属性注入前");
}
return true; // 返回false则跳过属性注入
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
if (bean instanceof LifecycleDemoBean) {
log.info("【步骤1.8】postProcessProperties:属性注入,@Autowired在这里处理");
}
return pvs;
}
}2.5 完整输出顺序(实际运行日志)
【步骤0.5】postProcessBeforeInstantiation:实例化之前,可以返回代理直接跳过实例化
【步骤1】构造器执行:实例化Bean
【步骤1.5】postProcessAfterInstantiation:实例化完成,属性注入前
【步骤1.8】postProcessProperties:属性注入,@Autowired在这里处理
【步骤2】属性注入:name = 老张的Bean
【步骤3】BeanNameAware.setBeanName:beanName = lifecycleDemoBean
【步骤4】BeanClassLoaderAware.setBeanClassLoader:AppClassLoader
【步骤5】BeanFactoryAware.setBeanFactory:DefaultListableBeanFactory
【步骤6】ApplicationContextAware.setApplicationContext:
【步骤7】BeanPostProcessor.postProcessBeforeInitialization:beanName = lifecycleDemoBean
【步骤8】@PostConstruct:所有属性已注入,可以做初始化了
【步骤9】InitializingBean.afterPropertiesSet:属性设置完毕
【步骤10】自定义init方法:customInit()
【步骤11】BeanPostProcessor.postProcessAfterInitialization:beanName = lifecycleDemoBean
...(应用运行中)...
【步骤12】@PreDestroy:容器即将关闭,做资源释放准备
【步骤13】DisposableBean.destroy:销毁Bean,释放资源三、各扩展点的实际用途
3.1 什么时候用哪个初始化方法
// 场景1:初始化连接池、线程池(推荐@PostConstruct,最简单)
@PostConstruct
public void initConnectionPool() {
this.pool = new ConnectionPool(config.getMaxSize());
pool.warmUp();
}
// 场景2:需要确保某个Bean已经注入才能初始化(用InitializingBean,能感知注入完成)
@Override
public void afterPropertiesSet() {
// 这里可以安全地使用所有@Autowired注入的依赖
if (this.dataSource == null) {
throw new IllegalStateException("DataSource必须配置");
}
}
// 场景3:第三方类,不能加注解(用@Bean的initMethod)
@Bean(initMethod = "start")
public ThirdPartyClient thirdPartyClient() {
return new ThirdPartyClient(config);
}3.2 BeanPostProcessor 的典型应用
Spring 框架自身大量使用 BeanPostProcessor:
| BeanPostProcessor 实现 | 作用 |
|---|---|
AutowiredAnnotationBeanPostProcessor | 处理 @Autowired、@Value |
CommonAnnotationBeanPostProcessor | 处理 @PostConstruct、@PreDestroy、@Resource |
AbstractAutoProxyCreator | 创建 AOP 代理(步骤11) |
ApplicationContextAwareProcessor | 处理各种 Aware 接口 |
四、踩坑实录
坑1:@PostConstruct 里注入的 Bean 是 null
症状:@PostConstruct 方法里用了 @Autowired 注入的 Bean,但是 null。
根因:从生命周期顺序来看,@PostConstruct 在属性注入(步骤2)之后执行,理论上不应该是 null。实际原因是:这个依赖的 Bean 还没有创建,存在循环依赖或者 Bean 创建顺序问题。
排查方式:加 @DependsOn("dependencyBeanName") 强制先创建依赖的 Bean。
坑2:@PostConstruct 和 InitializingBean 都用,执行顺序
结论:@PostConstruct(步骤8)先于 InitializingBean.afterPropertiesSet()(步骤9)执行。
很多人以为两个都实现会有冲突,实际上它们是不同的扩展点,各自独立执行,顺序固定。建议选一个用,推荐 @PostConstruct(更简单,不依赖 Spring 接口)。
坑3:BeanPostProcessor 本身不会被其他 BeanPostProcessor 处理
场景:你写了一个 BeanPostProcessor,想在它上面加 AOP,结果切面不生效。
根因:BeanPostProcessor 类型的 Bean 会被 Spring 提前实例化(在其他普通 Bean 之前),而 AOP 代理是在 postProcessAfterInitialization 里创建的,如果 AbstractAutoProxyCreator 本身还没有准备好,就无法代理提前实例化的 BeanPostProcessor。
Spring 会打印一条 WARN 日志:Bean 'xxx' of type [yyy] is not eligible for getting processed by all BeanPostProcessors,遇到这条日志就要注意了。
坑4:@PreDestroy 在某些场景下不执行
症状:应用被强制 kill(kill -9)时,@PreDestroy 没有执行,资源没有释放。
根因:kill -9 是 SIGKILL,操作系统强制终止进程,JVM 没有机会执行 Shutdown Hook。@PreDestroy 依赖 JVM 的 Shutdown Hook 机制。
kill -15(SIGTERM) 会触发 JVM Shutdown Hook,@PreDestroy 能正常执行。
建议:Docker/K8s 环境里的优雅停机,要配置 terminationGracePeriodSeconds,让应用有足够时间执行清理。
五、总结与延伸
Spring Bean 生命周期的 13 个关键步骤,记住这个顺序:
实例化 → 属性注入 → Aware → BPP前置 → @PostConstruct → afterPropertiesSet → initMethod → BPP后置 → 使用 → @PreDestroy → destroy
最常用的扩展点选型:
- 初始化逻辑:
@PostConstruct(80%场景) - 需要验证属性:
InitializingBean.afterPropertiesSet() - 要修改所有 Bean 的行为:
BeanPostProcessor - 要在实例化前短路(返回代理):
InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
