云计算百科
云计算领域专业知识百科平台

18 面试官:Spring Bean 的生命周期到底有多长?我看过源码,比你想象的复杂三倍

摘要:本文深入解析 Spring Bean 生命周期的 13 个核心步骤,从实例化、属性注入到初始化前后的 BeanPostProcessor 钩子机制。重点揭示了 AOP 代理在 postProcessAfterInitialization 阶段创建的底层原理,以及三级缓存解决循环依赖的关键设计。文章还对比了 BeanPostProcessor 与 BeanFactoryPostProcessor 的区别,并介绍了 @PostConstruct、SmartInitializingSingleton 等扩展钩子,帮助读者从源码层面掌握 Spring 容器的核心工作机制。

"Spring Bean 的生命周期是什么?"

这道题面试频率之高,几乎跟"HashMap 原理"一个级别。但你仔细回忆一下——大部分人的回答是不是就三句话:实例化、属性注入、初始化?

这没错,但你漏掉了一整层东西。

面试官真正想听的,是你知不知道BeanPostProcessor这个机制——它才是贯穿 Spring Bean 生命周期的灵魂。没有它,AOP 切不进去、事务管理跑不起来、@Autowired 根本不会工作。BeanPostProcessor 是在 Bean 初始化前后插入自定义逻辑的钩子,它的 intercept 能力是 Spring 所有扩展功能的基础。

今天就从头到尾过一遍 Spring Bean 的生命周期,每一阶段我告诉你源码在哪儿、做了什么、有什么用。


先把整体流程画出来

一个 Bean 从诞生到销毁,理论上经历五个阶段。但 Spring 在这五个阶段里嵌入了大量干预点。把干预点加上,实际的步骤是 13 步:

1. 实例化(反射创建对象)
2. 属性注入(设置各种属性值)
3. BeanNameAware.setBeanName()
4. BeanClassLoaderAware.setBeanClassLoader()
5. BeanFactoryAware.setBeanFactory()
6. BeanPostProcessor.postProcessBeforeInitialization()
7. InitializingBean.afterPropertiesSet()
8. 自定义 init-method
9. BeanPostProcessor.postProcessAfterInitialization() ← 🔥 AOP在这步
10. Bean 准备就绪,可以用了

11. DisposableBean.destroy()
12. 自定义 destroy-method
13. Bean 销毁

这里面最核心的是第 9 步——postProcessAfterInitialization()。AOP 的代理对象就是在这步创建的。Spring 的 AbstractAutoProxyCreator 实现了 BeanPostProcessor,在 postProcessAfterInitialization 里判断这个 Bean 是否需要代理——需要就创建代理对象替换原始 Bean。

如果你不理解 Bean 生命周期里有这个钩子,你永远想不通"为什么 @Transactional 在构造器里调用无效"——因为构造器在步骤 1 就执行完了,事务代理在步骤 9 才创建,构造器里当然拿不到代理对象。


第一步到第四步:从 class 到对象

Spring 容器启动时,AbstractApplicationContext.refresh() 方法被调用,这个方法有 13 个子步骤,Bean 的生命周期只是其中一环。

核心实现在 AbstractAutowireCapableBeanFactory.doCreateBean(),我把关键步骤拆出来:

// AbstractAutowireCapableBeanFactory.java — 核心流程(简化)
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
BeanWrapper instanceWrapper = null;
// 第一步:实例化
// 通过构造器反射创建对象实例
if (mbd.isSingleton()) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}

Object bean = instanceWrapper.getWrappedInstance();

// 第二步:早期暴露(解决循环依赖)
// 把半成品放入三级缓存 singletonFactories
// 这样别的 Bean 在循环依赖时可以拿到这个半成品
boolean earlySingletonExposure = mbd.isSingleton() &&
this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName);
if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

// 第三步:属性注入
// @Autowired、@Resource、@Value 都在这里处理
populateBean(beanName, mbd, instanceWrapper);

// 第四步:初始化(包括 Aware → Before → init → After)
Object exposedObject = initializeBean(beanName, exposedObject, mbd);

return exposedObject;
}

注意 addSingletonFactory 这步——把未完成属性注入的半成品对象放入三级缓存。这是 Spring 解决构造器循环依赖的关键。虽然属性注入的循环依赖靠二级缓存就够了,但三级缓存的存在是因为 AOP 代理需要在初始化后才创建。如果不用三级缓存,循环依赖时 AOP 代理对象就没办法正确创建。

每行源码都有它的意义。createBeanInstance 会判断用哪个构造器——如果你有多个构造器,Spring 会选参数最多的那个(或者你明确标注了 @Autowired 的那个)。populateBean 不只是设值,还会执行 InstantiationAwareBeanPostProcessor 的自定义注入逻辑。你自定义注解注入也是在这步通过处理器实现的。


第五步到第九步:各种 Aware 接口

initializeBean() 的内部实现是这样的:

// AbstractAutowireCapableBeanFactory.java — 初始化阶段
protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
// 第五步:调用 Aware 接口
invokeAwareMethods(beanName, bean);
// 第六步:Before 处理器
Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);

// 第七步 + 第八步:调用初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);

// 第九步:After 处理器 ← AOP 代理在这里
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

return wrappedBean;
}

invokeAwareMethods() 里执行的实际上是三个 Aware 的判断:

private void invokeAwareMethods(String beanName, Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(getBeanFactory());
}
}
}

只判断三个 Aware?等等——你不是说有十几个 Aware 吗?确实有:ApplicationContextAware、EnvironmentAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware 等等。但那些不是在 initializeBean() 里处理的——它们是在 ApplicationContextAwareProcessor(一个 BeanPostProcessor)的 postProcessBeforeInitialization 中处理的。也就是说,所有 ApplicationContext 相关的 Aware 是在第六步的 applyBeanPostProcessorsBeforeInitialization 中执行的,不是在第五步。

这给我们的教训是:Spring 把 Aware 分成了两类——容器核心 Aware(BeanName、BeanFactory 等)在 invokeAwareMethods 硬编码处理,应用上下文的 Aware 走 BeanPostProcessor 机制处理。这种分层设计说明了 Spring 源码的一个特点:能走扩展点走的,绝不硬编码。

顺便说一句,ApplicationContextAwareProcessor 本身就是一个内置的 BeanPostProcessor,它在 Spring 容器启动时由 refresh() 方法中的 prepareBeanFactory() 注册进去的。你在第六步的 postProcessBeforeInitialization 里能拿到 ApplicationContext,是因为这个处理器在 applyBeanPostProcessorsBeforeInitialization 遍历时执行了。这个过程对你来说是完全无感的——你只需要让你的 Bean 实现 ApplicationContextAware 接口,Spring 就会自动把 ApplicationContext 传进来。

再来看看第七步 invokeInitMethods 内部操作的顺序:

// 初始化方法调用顺序
protected void invokeInitMethods(String beanName, Object bean, RootBeanDefinition mbd) {
// 先调 InitializingBean 接口
if (bean instanceof InitializingBean) {
((InitializingBean) bean).afterPropertiesSet();
}
// 再调自定义 init-method(XML 配置或 @Bean(initMethod=…))
if (mbd.getInitMethodName() != null) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}

注意顺序:afterPropertiesSet 在前,自定义 init-method 在后。如果你的 Bean 同时实现了 InitializingBean 和配置了 init-method,afterPropertiesSet 会先执行。这个顺序在某些场景下很重要——比如你需要在 afterPropertiesSet 里验证所有必要属性已注入,然后在 init-method 里启动一些后台线程或订阅消息队列。

还有一个很多人忽略的细节:invokeCustomInitMethod 走的是反射,而且 Spring 会缓存这个 Method 对象,避免重复反射带来的性能开销。另外如果你的 init-method 的参数列表是 () 或者接收 (String, Object[]) 格式的,Spring 都能处理——但实际上大部分场景只需要无参方法。


第九步:AOP 代理就是在这里创建的

// AbstractAutoProxyCreator.java — 在 postProcessAfterInitialization 中创建代理
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
// 判断是否需要对当前 Bean 创建代理
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}

wrapIfNecessary 做的事:

1. 获取当前 Bean 所有的 Advisor(切面)

2. 用 Pointcut 匹配 Bean 的方法

3. 如果匹配上,通过 DefaultAopProxyFactory 创建代理

4. 返回代理对象替换原始 Bean

这个替换是透明的——容器里的 Bean 关联已经变成了代理对象,后续注入到其他 Bean 里的也是这个代理。

但这里有一个大坑:postProcessAfterInitialization 不只是 AOP 在用。 Spring 内部有很多内置的 BeanPostProcessor:AutowiredAnnotationBeanPostProcessor(处理 @Autowired)、RequiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor(处理 @Resource、@PostConstruct)等等。每个 BeanPostProcessor 的 order 决定了它们的执行顺序,这直接影响了你的 Bean 最终被处理成什么样。

如果这些处理器的顺序错了(或者你自己注册的 BeanPostProcessor 优先级不对),就会出现"为什么我的 @Autowired 没生效"这类问题。


BeanPostProcessor 和 BeanFactoryPostProcessor 的区别

这个也是面试高频混淆点。

BeanFactoryPostProcessor:在 Bean 实例化之前执行,操作的是 BeanDefinition(Bean 的定义元数据)。你可以修改 Bean 的 scope、lazy-init 标记、属性值等。执行时机在 refresh() 的 invokeBeanFactoryPostProcessors() 阶段。

BeanPostProcessor:在 Bean 实例化之后、初始化前后执行,操作的是 Bean 实例本身。你可以包装、替换、代理 Bean。

简单记忆:前者改配置,后者改对象。

还有一个容易被忽略的点:BeanFactoryPostProcessor 本身不支持 @Order 注解来排序——你必须实现 PriorityOrdered 或 Ordered 接口来控制执行顺序。这一点跟 BeanPostProcessor 的行为不一致,面试官偶尔会拿这个来考察候选人对源码的熟悉程度。


Spring 还提供了哪些生命周期钩子?

除了上面的核心 13 步,还有几个面试官可能会问的钩子:

@PostConstruct / @PreDestroy:JSR-250 规范定义的初始化/销毁方法,在 CommonAnnotationBeanPostProcessor 中处理。@PostConstruct 在 postProcessBeforeInitialization 中执行(在 afterPropertiesSet 之前),@PreDestroy 在 destroy 阶段执行。

SmartInitializingSingleton:在所有单例 Bean 都初始化完成后触发。afterSingletonsInstantiated() 方法在所有 Bean 创建完毕后调用一次,适合做全局后置处理——比如启动后检查所有依赖是否就绪。

Lifecycle 接口:start() 和 stop() 方法,主要用于管理容器生命周期内的启动和停止行为。Spring 容器会在 refresh() 的最后调用 startBeans()——所有实现了 Lifecycle 的 Bean 会按依赖顺序启动。这在 Spring Cloud 或消息队列的场景下特别有用,比如确保连接池在消息监听器启动之前就绪。

SmartLifecycle:Lifecycle 的增强版,多了 getPhase() 控制启动顺序,以及 isAutoStartup() 判断是否自动启动。如果你的应用需要热加载某些组件,用 SmartLifecycle 比用 @EventListener(ContextRefreshedEvent.class) 更优雅。


🎯 面试官视角的标准回答

"Spring Bean 的完整生命周期分为 13 步:实例化(通过构造器反射创建对象,同时放入三级缓存解决循环依赖)、属性注入(处理 @Autowired、@Resource、@Value)、Aware 接口调用(BeanName、BeanClassLoader、BeanFactory 三个硬编码 + 其他通过 BeanPostProcessor)、BeanPostProcessor 的 Before 处理器(执行 @PostConstruct)、InitializingBean 的 afterPropertiesSet、自定义 init-method、BeanPostProcessor 的 After 处理器(AOP 代理就是在这步创建的,AbstractAutoProxyCreator 的 wrapIfNecessary 方法判断是否需要代理)、Bean 就绪、销毁阶段(@PreDestroy、DisposableBean.destroy、自定义 destroy-method)。核心理解:BeanPostProcessor 是 Spring 扩展功能的基石——没有它,AOP、事务、@Autowired 全部无法工作。区分 BeanFactoryPostProcessor(操作 BeanDefinition、在实例化前执行)和 BeanPostProcessor(操作 Bean 实例、在初始化前后执行)。有两个容易被忽略的钩子:SmartInitializingSingleton(所有单例都初始化后触发)和 SmartLifecycle(容器级别的 start/stop 管理)。"


下篇预告:面试官问线程池,大部分人只背了七个参数。下一篇文章聊 ThreadPoolExecutor 的核心源码——队列满了怎么办、拒绝策略怎么选、核心线程数到底设多少合适。

>

赞(0)
未经允许不得转载:网硕互联帮助中心 » 18 面试官:Spring Bean 的生命周期到底有多长?我看过源码,比你想象的复杂三倍
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!