Spring Bean 生命周期全解析
候选人小周在面试蚂蚁时,面试官问了一个经典问题:
"Spring Bean 的生命周期说一下。"
小周答:"先实例化,然后设置属性,再初始化,最后销毁。"
面试官追问:"具体有哪些回调接口?Aware 接口什么时候执行?BeanPostProcessor 在哪个阶段工作?"
小周支支吾吾,说了五六个节点就开始卡壳了。
面试官继续追问:"InitializingBean 和 init-method 谁先执行?BeanPostProcessor 和 InitializingBean 的执行顺序是什么?"
小周彻底答不上来。
【面试官心理】
Bean 生命周期是 Spring 面试中的高频考点。90%的候选人能说出大概流程,但能完整说出12个节点、搞清Aware接口顺序、说清 BeanPostProcessor 和 InitializingBean 关系的不到20%。这道题是区分"看过几篇博客"和"真正研究过源码"的分水岭。
一、Bean 生命周期12步全景 🔴
1.1 完整流程图
graph TD
A[1. 实例化<br/>instantiateBean] --> B[2. 实例化后处理<br/>addSingletonFactory]
B --> C[3. 属性填充<br/>populateBean]
C --> D[4. Aware 接口回调<br/>invokeAwareMethods]
D --> E[5. BeanPostProcessor前置<br/>postProcessBeforeInitialization]
E --> F[6. 初始化<br/>invokeInitMethods]
F --> G[7. BeanPostProcessor后置<br/>postProcessAfterInitialization]
G --> H[8. 使用]
H --> I[9. 销毁前回调<br/>destroy()开始]
I --> J[10. 销毁前自定义<br/>destroyMethod]
J --> K[11. 销毁<br/>DisposableBean.destroy]
K --> L[12. 清理]
1.2 ❌ 错误示范
候选人原话:"Bean 生命周期就是:创建 -> 设置属性 -> 初始化 -> 销毁。"
问题诊断:
- 只说了大概流程,没有具体节点
- 不知道Aware接口的具体作用时机
- 不知道 BeanPostProcessor 在初始化前后的两次机会
- 不知道 init-method 和 InitializingBean 的关系
【面试官心理】
Bean 生命周期的每个节点都是一个"钩子",Spring 框架本身(@Autowired、@Resource、AOP)就挂在这些钩子上工作。知道这些节点,才能理解 Spring 是怎么扩展的,才能理解为什么某些操作(循环依赖、AOP)会在特定阶段出问题。
1.3 12个关键节点详解
第1步:实例化(Instantiation)
// AbstractAutowireCapableBeanFactory.createBeanInstance()
BeanWrapper instanceWrapper = createBeanInstance(
beanName, mbd, constructorOrFactoryMethod, args);
// 使用策略模式选择实例化方式
InstantiationStrategy strategy = new CglibSubclassingInstantiationStrategy();
Object bean = strategy.instantiate(mbd, beanName, owner, ctor, args);
// 关键:此时 Bean 实例已经创建出来了
// 但还没有任何属性、还没有设置Aware接口
第2步:实例化后处理(Early Bean Reference)
// AbstractAutowireCapableBeanFactory.doCreateBean()
protected void doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
BeanWrapper instanceWrapper = createBeanInstance(...);
// 将工厂加入三级缓存,用于解决循环依赖
// 注意:构造器注入在此之前就卡死了,所以无法提前暴露
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
// 此时填充属性还未执行
populateBean(beanName, mbd, instanceWrapper);
}
第3步:属性填充(PopulateBean)
// AbstractAutowireCapableBeanFactory.populateBean()
populateBean(beanName, mbd, instanceWrapper);
// 处理 @Autowired、@Resource 等注解
// AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues()
// 对所有属性进行依赖注入
第4步:Aware 接口回调
// AbstractAutowireCapableBeanFactory.invokeAwareMethods()
private void invokeAwareMethods(String beanName, Object bean) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(getClassLoader());
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(this);
}
}
// ApplicationContextAware 在 ApplicationContextAwareProcessor 中处理
// ApplicationContextAwareProcessor.postProcessBeforeInitialization()
Aware 接口顺序:
// Spring 内部的执行顺序(不可改变)
BeanNameAware → setBeanName() // Bean 的名字
BeanClassLoaderAware → setBeanClassLoader() // 类加载器
BeanFactoryAware → setBeanFactory() // BeanFactory 引用
// ---- ApplicationContext 特有 ----
EnvironmentAware → setEnvironment() // 环境变量
EmbeddedValueResolverAware → setEmbeddedValueResolver() // 值解析器
ApplicationContextAware → setApplicationContext() // ApplicationContext 引用
⚠️
BeanFactoryAware 和 ApplicationContextAware 是互斥的。如果你实现了 BeanFactoryAware,Spring 会回调它;如果你实现了 ApplicationContextAware,Spring 会通过 ApplicationContextAwareProcessor 来回调。两者混用时,Spring 会优先使用 ApplicationContextAwareProcessor。
第5步:BeanPostProcessor 前置处理
// AbstractAutowireCapableBeanFactory.initializeBean()
protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
// Aware 回调已经完成
// 第5步:BeanPostProcessor.postProcessBeforeInitialization()
Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
// 第6步:初始化方法
// 第7步:BeanPostProcessor.postProcessAfterInitialization()
wrappedBean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
Spring 内置的 BeanPostProcessor(按执行顺序):
第6步:初始化方法
// 执行顺序:先 InitializingBean,再 init-method
// 方式一:InitializingBean 接口
public class UserService implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
// 初始化逻辑
}
}
// 方式二:@PostConstruct 注解(推荐,优先级高于 InitializingBean)
public class UserService {
@PostConstruct
public void init() {
// 初始化逻辑
}
}
// 方式三:init-method 配置
// <bean id="userService" class="com.example.UserService" init-method="init"/>
// 方式四:@Bean(initMethod = "init")
// @Bean(initMethod = "init")
// public UserService userService() { return new UserService(); }
执行顺序:@PostConstruct -> InitializingBean.afterPropertiesSet() -> init-method
// InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization()
public Object postProcessBeforeInitialization(
Object bean, String beanName) throws BeansException {
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
metadata.invokeInitMethods(bean, beanName); // 执行 @PostConstruct
return bean;
}
// AbstractAutowireCapableBeanFactory.invokeInitMethods()
protected void invokeInitMethods(String beanName, Object bean,
RootBeanDefinition mbd) throws Throwable {
// 先执行 @PostConstruct(通过 BeanPostProcessor)
// 再执行 InitializingBean
if (bean instanceof InitializingBean) {
((InitializingBean) bean).afterPropertiesSet();
}
// 最后执行 init-method
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
第7步:BeanPostProcessor 后置处理
// 在初始化方法执行后,BeanPostProcessor 再次介入
// 这里是 AOP 代理创建的关键时机!
wrappedBean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
// 如果有切面切中了这个 Bean
// AnnotationAwareAspectJAutoProxyCreator.postProcessAfterInitialization()
// 会在这里创建代理对象,替换原始 Bean
💡
BeanPostProcessor 的后置处理是 AOP 代理创建的核心时机。Spring AOP 通过 AbstractAutoProxyCreator.postProcessAfterInitialization() 在这里判断是否需要为 Bean 创建代理。如果一个 Bean 被 AOP 切中,这里返回的就不是原始对象,而是代理对象了。
二、Bean 销毁生命周期 🟡
2.1 销毁顺序
// 销毁的执行顺序
// 1. @PreDestroy 注解的方法
// 2. DisposableBean.destroy()
// 3. destroy-method 配置的方法
public class UserService {
@PreDestroy
public void beforeDestroy() {
// 第一步执行
}
}
public class UserServiceImpl implements DisposableBean {
@Override
public void destroy() throws Exception {
// 第二步执行
}
}
// destroy-method
// <bean id="userService" destroy-method="cleanup"/>
三、Bean 作用域 🟡
3.1 四种作用域
@Scope("prototype")
@Component
public class OrderService {
// 每次 getBean 都创建新实例
}
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
@Component
public class UserContext {
// 代理模式解决注入问题
// 在 request 作用域 Bean 注入到 singleton Bean 时必须使用代理
}
3.2 prototype 作用域的坑
@Service
public class OrderService {
@Autowired
private OrderDAO orderDAO; // orderDAO 是 prototype 作用域
}
// 问题:OrderService 是 singleton,orderDAO 只注入一次
// 每次调用的都是同一个 orderDAO 实例!
// 解决方式:延迟获取
@Service
public class OrderService {
@Autowired
private ObjectFactory<OrderDAO> orderDAOFactory;
public void createOrder() {
OrderDAO dao = orderDAOFactory.getObject(); // 每次获取新实例
}
}
四、自定义 BeanPostProcessor 🟡
4.1 实战案例
// 自定义 BeanPostProcessor:自动记录 Bean 创建日志
@Component
public class LoggingBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(
Object bean, String beanName) throws BeansException {
System.out.println("Bean [" + beanName + "] 开始初始化");
return bean;
}
@Override
public Object postProcessAfterInitialization(
Object bean, String beanName) throws BeansException {
System.out.println("Bean [" + beanName + "] 初始化完成");
return bean;
}
}
4.2 InstantiationAwareBeanPostProcessor
// 更强大的后置处理器:在实例化前后都可以干预
@Component
public class MyInstantiationAwareBeanPostProcessor
extends InstantiationAwareBeanPostProcessorAdapter {
// 实例化之前返回替代品
@Override
public Object postProcessBeforeInstantiation(
Class<?> beanClass, String beanName) throws BeansException {
if (beanClass == OrderService.class) {
// 返回一个代理对象,完全替代默认实例化
return createProxy(beanClass);
}
return null; // 返回 null 表示继续默认实例化
}
// 实例化之后、属性填充之前
@Override
public boolean postProcessAfterInstantiation(
Object bean, String beanName) throws BeansException {
// 返回 false 可以阻止属性填充
return true;
}
}
五、生产避坑 🟡
5.1 初始化顺序导致的 NPE
@Component
public class UserService implements InitializingBean {
@Autowired
private OrderService orderService;
private String config;
@Override
public void afterPropertiesSet() throws Exception {
// 问题:此时 orderService 可能还没注入!
// afterPropertiesSet 在属性填充后执行,但如果是循环依赖...
orderService.getOrder();
}
}
5.2 循环依赖与代理对象的坑
@Component
public class A {
@Autowired
private B b;
public void doSomething() {
// 假设这里需要 A 的代理对象
A proxy = (A) AopContext.currentProxy();
}
}
@Component
public class B {
@Autowired
private A a;
}
如果 A 有 AOP 切面,在构造器注入循环依赖下,AopContext.currentProxy() 会返回原始对象(因为 Bean 还没完成初始化,代理还没创建)。
5.3 destroy-method 的遗漏
@Service
public class MyService {
private ThreadPoolExecutor executor;
@PostConstruct
public void init() {
executor = new ThreadPoolExecutor(...);
}
// 问题:没有 destroy-method,线程池不会被关闭!
// 如果 Bean 实现了 DisposableBean 或配置了 destroy-method,就能正常关闭
@PreDestroy
public void shutdown() {
executor.shutdown();
}
}
六、工程选型 🟢
6.1 初始化方式的选择
【面试官心理】
我通常会问候选人:"如果 @PostConstruct 和 InitializingBean 同时存在,谁先执行?" 能答出"@PostConstruct 先执行"并解释原因的,是真正看过源码的。如果连这个都答错,说明要么没看过源码,要么记混了。
七、面试追问链 🔴
第一层:基本流程
面试官问:"Spring Bean 的生命周期有哪些阶段?"
候选人答:"创建、属性填充、初始化、销毁..."(说不完整)
考察点:基本认知
第二层:详细节点
面试官追问:"Aware 接口有哪些?它们的执行顺序是什么?"
候选人答:...(容易混淆)
考察点:源码细节
第三层:执行顺序
面试官追问:"@PostConstruct、InitializingBean、init-method 的执行顺序是什么?BeanPostProcessor 在哪里插入?"
候选人答:...(核心难点)
考察点:执行顺序理解
第四层:扩展应用
面试官追问:"如果要自定义 Bean 的创建过程,在实例化之前做点什么,该怎么做?"
候选人答:...(InstantiationAwareBeanPostProcessor)
考察点:实际应用
第五层:生产问题
面试官追问:"Bean A 依赖 B,B 依赖 C,C 依赖 A,构造器注入和 setter 注入的循环依赖处理有什么不同?"
候选人答:...(综合应用)
考察点:深度理解