面试专题

Spring Bean 生命周期有哪些阶段?都有哪些扩展点?

系统讲解 Spring 容器启动、Bean 定义处理、实例化、属性注入、初始化、AOP 代理、就绪与销毁的完整生命周期,并梳理 BeanFactoryPostProcessor、BeanPostProcessor、Aware、初始化回调、SmartInitializingSingleton、事件和 SmartLifecycle 等扩展点。

难度:深入更新:2026-07-27

Spring Bean 生命周期有哪些阶段?都有哪些扩展点?

面试回答

Spring Bean 的完整生命周期可以分为:Bean 定义注册与修改、实例化、属性填充、Aware 回调、初始化前处理、初始化、初始化后处理、Bean 就绪,以及容器关闭时的销毁

容器启动后,首先读取配置并注册 BeanDefinitionBeanDefinitionRegistryPostProcessor 可以继续注册或删除定义,BeanFactoryPostProcessor 可以在 Bean 创建前修改定义。随后 Spring 注册所有 BeanPostProcessor,再创建非懒加载单例。

创建单个 Bean 时,Spring先选择构造方法并实例化对象,再进行依赖注入;随后执行 Aware 回调、BeanPostProcessor#postProcessBeforeInitialization()@PostConstructInitializingBean#afterPropertiesSet() 和自定义 init-method,最后执行 postProcessAfterInitialization()。Spring AOP 通常在初始化后处理阶段返回代理对象。

所有普通非懒加载单例创建完成后,可以使用 SmartInitializingSingleton 或监听 ContextRefreshedEvent 执行全局初始化;需要管理组件启动和停止顺序时,可以使用 SmartLifecycle。容器关闭时,先由 DestructionAwareBeanPostProcessor 执行销毁前处理,其中 CommonAnnotationBeanPostProcessor 会调用 @PreDestroy;之后再执行 DisposableBean#destroy() 和自定义销毁方法。

一句话总结:

Spring 先处理 BeanDefinition,再通过 BeanPostProcessor 贯穿 Bean 的创建过程;Bean 初始化完成不等于容器全部就绪,批量就绪、运行启停和销毁分别有对应扩展点。

一张图看懂

Spring 容器启动、Bean 创建、就绪运行和销毁阶段及主要扩展点

详细讲解

一、先区分两个生命周期

讨论“Spring 生命周期”时,容易把两个概念混在一起:

1. ApplicationContext 容器生命周期

容器负责:

加载配置
→ 注册和修改 BeanDefinition
→ 注册容器级后处理器
→ 创建非懒加载单例
→ 发布刷新完成事件
→ 启动 Lifecycle 组件
→ 关闭并销毁单例

2. 单个 Bean 的生命周期

单个 Bean 经历:

实例化
→ 属性填充
→ Aware 回调
→ 初始化前处理
→ 初始化回调
→ 初始化后处理
→ 对外提供
→ 销毁

BeanFactoryPostProcessor 作用于整个容器中的 Bean 定义;BeanPostProcessor 作用于容器创建的 Bean 实例。两者所处层次不同。

二、阶段一:加载并注册 BeanDefinition

BeanDefinition 是 Spring 创建 Bean 的配置模型,记录了:

  • Bean 类型;
  • 作用域;
  • 是否懒加载;
  • 构造参数和属性值;
  • 初始化方法和销毁方法;
  • 依赖关系;
  • 是否允许作为自动注入候选项。

Bean 定义可能来自:

  • @Component 组件扫描;
  • @Bean 方法;
  • XML;
  • 程序化注册;
  • @Import 导入。

这一阶段还没有创建普通业务 Bean,处理的是“如何创建 Bean”的元数据。

1. ImportSelector

ImportSelector 根据导入类的元数据,返回需要注册的配置类名称。

适合:

  • 按条件组合一组配置;
  • 模块化装配;
  • 框架自动配置入口。

DeferredImportSelector 会在普通配置类处理之后再决定导入内容,Spring Boot 自动配置大量使用了这类机制。

2. ImportBeanDefinitionRegistrar

ImportBeanDefinitionRegistrar 可以直接向注册表写入 BeanDefinition

适合:

  • 根据注解属性动态注册 Bean;
  • 为接口生成代理 BeanDefinition;
  • 注册数量或名称在编译期不固定的组件。

3. BeanDefinitionRegistryPostProcessor

它是 BeanFactoryPostProcessor 的子接口,核心能力是操作 BeanDefinitionRegistry

public interface BeanDefinitionRegistryPostProcessor
        extends BeanFactoryPostProcessor {

    void postProcessBeanDefinitionRegistry(
            BeanDefinitionRegistry registry);
}

它可以在普通 BeanFactoryPostProcessor 执行前:

  • 注册新的 BeanDefinition;
  • 删除或替换已有 BeanDefinition;
  • 扫描额外的组件;
  • 根据外部配置动态扩展容器。

ConfigurationClassPostProcessor 就是重要实现,它负责解析 @Configuration@ComponentScan@Import@Bean 等配置。

三、阶段二:修改 BeanDefinition

BeanFactoryPostProcessor

所有 BeanDefinition 基本注册完成后,Spring 调用 BeanFactoryPostProcessor

public interface BeanFactoryPostProcessor {

    void postProcessBeanFactory(
            ConfigurableListableBeanFactory beanFactory);
}

它处理的是 BeanDefinition,而不是已经创建好的业务对象。

典型能力包括:

  • 修改属性值;
  • 修改作用域和懒加载配置;
  • 调整自动注入候选状态;
  • 解析配置占位符;
  • 注册容器级基础设施。

例如 PropertySourcesPlaceholderConfigurer 会把:

order.timeout=${ORDER_TIMEOUT}

中的占位符替换为环境中的实际值。

不要在这个阶段随意调用 getBean()。这会导致普通 Bean 提前创建,使它可能绕过尚未注册完成的 BeanPostProcessor,进而错过依赖注入、AOP 等处理。

四、阶段三:注册 BeanPostProcessor

Spring 会提前创建并注册所有 BeanPostProcessor,使它们能够处理后续创建的 Bean。

基础接口如下:

public interface BeanPostProcessor {

    default Object postProcessBeforeInitialization(
            Object bean, String beanName) {
        return bean;
    }

    default Object postProcessAfterInitialization(
            Object bean, String beanName) {
        return bean;
    }
}

常见功能很多都建立在 BeanPostProcessor 体系上:

  • @Autowired@Value 注入;
  • @PostConstruct@PreDestroy
  • AOP 自动代理;
  • @Async
  • @Scheduled
  • 事务代理;
  • 异常转换。

执行顺序

多个后处理器通常按照以下优先级排序:

PriorityOrdered
→ Ordered
→ 未实现排序接口

程序化调用 addBeanPostProcessor() 注册时,主要按照实际注册顺序执行,不应只依赖 Ordered

五、阶段四:实例化 Bean

Spring 在 AbstractAutowireCapableBeanFactory#createBean() 中进入单个 Bean 的创建流程。

1. 实例化前扩展

InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation() 在目标对象真正实例化前执行。

它可以直接返回一个对象,例如代理:

返回 null
→ 继续正常实例化流程

返回非 null
→ 跳过普通实例化、属性填充和初始化流程
→ 对返回对象执行初始化后处理

这属于特殊扩展点,主要用于框架基础设施,不适合承载普通业务初始化。

2. 选择构造方法

Spring需要决定使用:

  • 默认构造方法;
  • 显式指定的构造方法;
  • @Autowired 构造方法;
  • 工厂方法;
  • Supplier

SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors() 可以参与候选构造方法选择。

3. 创建原始对象

构造方法或工厂方法执行完成后,得到的是原始 Bean 实例。此时依赖属性通常还没有填充,初始化回调也没有执行。

六、阶段五:处理合并后的 BeanDefinition

父子 BeanDefinition、配置覆盖和类型解析完成后,Spring 得到合并后的 BeanDefinition。

MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition() 可以缓存与具体 Bean 类型有关的元数据。

常见用途包括:

  • 扫描注入点;
  • 缓存注解元数据;
  • 为后续属性注入和销毁处理做准备。

AutowiredAnnotationBeanPostProcessor 会在这里分析 @Autowired@Value 等注入信息,避免每次都重新反射扫描。

七、阶段六:提前暴露引用

对于允许循环依赖处理的单例,Spring可能在属性填充前暴露一个对象工厂:

singletonFactories
→ earlySingletonObjects
→ singletonObjects

这里暴露的不是“已经完成初始化的 Bean”,而是用于打破依赖环的早期引用。

SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference() 可以决定早期暴露什么对象。AOP 自动代理创建器会利用这个扩展点,尽量让循环依赖中的其他 Bean 获得代理引用,而不是直接获得原始对象。

需要注意:

  • 这主要处理单例的属性或 Setter 注入循环依赖;
  • 构造器循环依赖无法靠提前暴露一个尚未构造完成的对象解决;
  • 原型 Bean 的循环依赖也不能通过三级缓存解决;
  • 不应把三级缓存当成设计循环依赖的理由。

八、阶段七:属性填充与依赖注入

实例创建后,Spring进入 populateBean(),为对象填充依赖。

1. postProcessAfterInstantiation

InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation() 在对象已经实例化、属性填充尚未开始时执行。

返回 false 可以阻止 Spring继续执行常规属性填充,因此属于影响较大的底层扩展点。

2. postProcessProperties

InstantiationAwareBeanPostProcessor#postProcessProperties() 可以处理属性注入。

典型实现:

  • AutowiredAnnotationBeanPostProcessor:处理 @Autowired@Value
  • CommonAnnotationBeanPostProcessor:处理 @Resource 等 Jakarta 注解。

随后 Spring还会应用 BeanDefinition 中显式配置的属性值。

九、阶段八:Aware 回调

依赖注入完成后,Spring让 Bean 感知容器提供的基础设施。

常见接口包括:

Aware 接口能够获得的对象
BeanNameAware当前 Bean 名称
BeanClassLoaderAwareBean 类加载器
BeanFactoryAware当前 BeanFactory
EnvironmentAwareEnvironment
ApplicationEventPublisherAware事件发布器
ResourceLoaderAware资源加载器
ApplicationContextAwareApplicationContext

前三个由 BeanFactory 初始化流程直接调用;ApplicationContextAware 等接口通常由 ApplicationContextAwareProcessor 这个 BeanPostProcessor 处理。

Aware 适合获取容器基础设施,但会让业务类与 Spring 接口耦合。普通业务依赖仍应优先采用构造器注入。

十、阶段九:初始化前处理

Spring依次调用所有:

BeanPostProcessor#postProcessBeforeInitialization()

常见用途包括:

  • 识别并执行生命周期注解;
  • 对 Bean 做初始化前检查;
  • 注入容器上下文相关能力;
  • 包装或替换 Bean。

@PostConstruct 在哪里执行

@PostConstruct 不是 Spring硬编码在初始化流程中的独立步骤,而是由 CommonAnnotationBeanPostProcessor 在初始化前处理阶段识别并调用。

因此从宏观顺序看:

Aware 回调
→ postProcessBeforeInitialization
   → @PostConstruct
→ InitializingBean
→ 自定义 init-method

十一、阶段十:执行初始化回调

同一个 Bean 同时使用多种初始化机制且方法名不同时,调用顺序是:

  1. @PostConstruct
  2. InitializingBean#afterPropertiesSet()
  3. @Bean(initMethod = "...") 或 XML init-method

示例:

public class PaymentClient implements InitializingBean {

    @PostConstruct
    public void validateConfiguration() {
        // 校验配置
    }

    @Override
    public void afterPropertiesSet() {
        // Spring 接口回调
    }

    public void init() {
        // 自定义初始化方法
    }
}

配置:

@Bean(initMethod = "init", destroyMethod = "close")
public PaymentClient paymentClient() {
    return new PaymentClient();
}

业务代码通常优先选择 @PostConstruct 或自定义初始化方法,避免为了生命周期回调而强耦合 Spring 接口。

初始化方法适合:

  • 校验必要配置;
  • 构造只依赖当前 Bean 状态的内存结构;
  • 完成本地资源准备。

不适合在初始化方法中启动复杂异步任务,或者访问大量其他 Bean。初始化发生在单例创建过程中,过重或存在交叉访问的逻辑可能延长启动时间,甚至引发初始化死锁。

十二、阶段十一:初始化后处理与 AOP 代理

初始化回调完成后,Spring调用:

BeanPostProcessor#postProcessAfterInitialization()

后处理器可以返回:

  • 原对象;
  • 包装对象;
  • 代理对象;
  • 其他兼容对象。

Spring AOP 的自动代理创建器属于 BeanPostProcessor。它会判断当前 Bean 是否匹配 Advisor;如果匹配,就创建 JDK 动态代理或 CGLIB 代理。

因此容器最终对外暴露的对象可能不是原始对象:

原始 Bean
→ 初始化回调
→ AOP 后处理器
→ 代理 Bean
→ singletonObjects

这也解释了为什么在 @PostConstruct 中调用自身的事务方法,通常不会经过当前 Bean 的事务代理:初始化回调执行时,完整代理尚未作为最终 Bean 对外提供,而且调用方式仍然是对象内部的 this 调用。

十三、Bean 初始化完成后,容器何时才算就绪

单个 Bean 完成初始化,并不代表所有单例都已经创建完成。

1. SmartInitializingSingleton

所有常规非懒加载单例完成实例化后,Spring调用:

public interface SmartInitializingSingleton {

    void afterSingletonsInstantiated();
}

适合:

  • 需要确认其他单例已经准备完成的检查;
  • 汇总多个 Bean 建立注册表;
  • 避免因为主动 getBeansOfType() 导致意外提前初始化。

它只对单例 Bean 有意义。

2. ContextRefreshedEvent

容器刷新完成后会发布 ContextRefreshedEvent

可以使用:

@EventListener(ContextRefreshedEvent.class)
public void onContextReady() {
    // 容器刷新完成后的逻辑
}

适合需要基于 ApplicationContext 刷新完成事件触发的逻辑。

需要注意,ApplicationContext 可以被刷新多次时,监听逻辑也可能执行多次,业务代码应考虑幂等。

3. SmartLifecycle

需要启动和停止后台消费者、调度器、长连接等有运行状态的组件时,优先考虑 SmartLifecycle

public interface SmartLifecycle extends Lifecycle, Phased {

    boolean isAutoStartup();

    void stop(Runnable callback);
}

它支持:

  • 容器刷新后自动启动;
  • phase 控制启动和停止顺序;
  • 异步停止完成回调;
  • 运行状态检查。

启动时通常先启动较小的 phase,关闭时反向停止。依赖其他组件的服务应根据依赖关系设计 phase,而不是随意填写。

十四、阶段十二:容器关闭与 Bean 销毁

容器正常关闭时,Spring先停止需要运行期管理的 Lifecycle 组件,再销毁受管理的单例 Bean。

同一个 Bean 配置多种销毁机制且方法名不同时,可以按下面的层次理解:

  1. DestructionAwareBeanPostProcessor#postProcessBeforeDestruction() 执行销毁前处理,其中 CommonAnnotationBeanPostProcessor 调用 @PreDestroy
  2. DisposableBean#destroy()
  3. @Bean(destroyMethod = "...") 或 XML destroy-method

因此,@PreDestroy 不是脱离后处理器单独运行的一轮流程,而是 DestructionAwareBeanPostProcessor 体系提供的具体生命周期回调。

销毁阶段适合:

  • 停止后台任务;
  • 关闭线程池;
  • 关闭网络连接;
  • 刷新缓冲数据;
  • 注销服务或监听器。

原型 Bean 的特殊点

对于 prototype Bean,Spring负责创建和注入,但把实例交给调用方后通常不再跟踪其完整生命周期,因此不会自动调用普通销毁回调。

如果原型 Bean 持有必须释放的资源,应由使用方显式关闭,或者改用更合适的作用域和资源管理方式。

应用被强制终止时,销毁回调也不保证一定执行。重要数据不能只依赖 @PreDestroy 才落盘。

十五、常见扩展点应该怎么选择

目标优先考虑的扩展点
导入一组配置类ImportSelectorDeferredImportSelector
动态注册 BeanDefinitionImportBeanDefinitionRegistrarBeanDefinitionRegistryPostProcessor
在创建 Bean 前修改配置元数据BeanFactoryPostProcessor
自定义注入、实例化或代理BeanPostProcessor 及其子接口
获得 Bean 名称或容器对象对应的 Aware 接口
依赖注入完成后校验当前 Bean@PostConstruct 或自定义 initMethod
所有普通单例创建完成后执行SmartInitializingSingleton
容器刷新完成后执行监听 ContextRefreshedEvent
管理后台组件的启动和停止SmartLifecycle
释放 Bean 自身资源@PreDestroy 或自定义 destroyMethod
创建复杂对象并把产物交给容器FactoryBean
定义新的 Bean 作用域实现 Scope 并注册

十六、FactoryBean 是什么扩展点

普通 BeanDefinition 描述“这个类本身如何被创建”;FactoryBean<T> 描述“通过这个工厂生产什么对象”。

public interface FactoryBean<T> {

    T getObject() throws Exception;

    Class<?> getObjectType();

    default boolean isSingleton() {
        return true;
    }
}

假设 Bean 名称为 clientFactory

getBean("clientFactory")
→ 获得 FactoryBean 生产的对象

getBean("&clientFactory")
→ 获得 FactoryBean 本身

它适合创建代理、客户端、会话工厂等构造过程复杂的对象。MyBatis 与 Spring 集成中的 SqlSessionFactoryBean 就使用了这一机制。

十七、自定义 Scope

默认常见作用域包括:

  • singleton
  • prototype
  • Web 环境中的 requestsessionapplicationwebsocket

实现 org.springframework.beans.factory.config.Scope 并通过 ConfigurableBeanFactory#registerScope() 注册,可以定义租户、任务、线程上下文等自定义作用域。

自定义 Scope 必须明确:

  • 实例保存在哪里;
  • 何时创建和复用;
  • 上下文结束时如何执行销毁回调;
  • 上下文如何跨线程传播;
  • 作用域 Bean 被单例依赖时是否需要代理。

十八、常见误区

1. Bean 构造完成就可以使用

构造完成后还没有完成属性注入、Aware、初始化回调和后处理,不能把构造完成等同于 Bean 就绪。

2. @PostConstruct 发生在 AOP 代理之后

@PostConstruct 属于初始化前处理阶段;AOP 代理通常在初始化后处理中形成并作为最终对象暴露。

3. BeanPostProcessor 只在初始化前后各做一次简单回调

基础接口只有两个方法,但其子接口参与实例化前、构造器选择、属性填充、早期代理、合并定义和销毁等多个阶段。

4. BeanFactoryPostProcessor 可以直接修改业务 Bean

它应该修改 BeanDefinition。调用 getBean() 可能造成提前实例化并绕过其他基础设施。

5. Bean 生命周期结束一定会执行销毁方法

原型 Bean、进程强杀、机器掉电等场景都可能无法执行正常销毁回调。

6. 所有初始化逻辑都放进 @PostConstruct

Bean 自身的轻量校验可以放在 @PostConstruct;依赖所有单例完成、容器刷新完成或需要启停管理的任务,应分别选择 SmartInitializingSingleton、容器事件或 SmartLifecycle

十九、源码主线

阅读 Spring Bean 生命周期源码时,可以沿着以下调用链:

AbstractApplicationContext#refresh
├── invokeBeanFactoryPostProcessors
├── registerBeanPostProcessors
├── finishBeanFactoryInitialization
│   └── preInstantiateSingletons
│       └── getBean
│           └── AbstractAutowireCapableBeanFactory#createBean
│               └── doCreateBean
│                   ├── createBeanInstance
│                   ├── applyMergedBeanDefinitionPostProcessors
│                   ├── addSingletonFactory
│                   ├── populateBean
│                   └── initializeBean
│                       ├── invokeAwareMethods
│                       ├── applyBeanPostProcessorsBeforeInitialization
│                       ├── invokeInitMethods
│                       └── applyBeanPostProcessorsAfterInitialization
└── finishRefresh

销毁主线可以关注:

AbstractApplicationContext#close
→ doClose
→ LifecycleProcessor#onClose
→ destroyBeans
→ DisposableBeanAdapter#destroy

二十、复习检查清单

  • 能否区分容器生命周期和单个 Bean 生命周期;
  • 能否说明 BeanFactoryPostProcessorBeanPostProcessor 的区别;
  • 是否知道依赖注入发生在实例化之后、初始化之前;
  • 能否说清 @PostConstructInitializingBean、自定义 init 方法的顺序;
  • 是否知道 AOP 代理通常在哪个阶段创建;
  • 能否解释三级缓存和 getEarlyBeanReference() 的作用;
  • 是否知道单个 Bean 初始化完成后还有哪些容器级扩展点;
  • 能否说明 SmartInitializingSingleton、容器事件和 SmartLifecycle 的使用边界;
  • 是否知道销毁回调的顺序以及原型 Bean 的限制;
  • 能否按目标选择定义级、实例级、运行级和销毁级扩展点。

参考资料

DISCUSSION

评论与讨论

留下你的想法