在开发自定义 Starter(如封装 RocketMQ、Redis 客户端、内部中间件)时,你是否曾思考:
- 如何在用户只写一个注解的情况下,自动注册消费者?
- 如何在容器启动后统一启动所有组件?
- 如何在应用关闭时优雅释放资源?
这些问题的答案,都藏在 Spring Boot 提供的一系列生命周期扩展点中。
本文将按执行顺序 系统梳理 Spring(及 Spring Boot)为框架/基础设施层提供的核心扩展机制,助你构建健壮、可维护的 Starter 或中间件封装。
📅 一、整体生命周期概览
Spring 容器的启动与关闭是一个高度结构化的过程。作为框架开发者,我们需要在合适的时机"插入"自己的逻辑:
css
[启动前]
→ [Bean 定义处理]
→ [Bean 实例化与初始化]
→ [所有单例就绪]
→ [运行期事件]
→ [关闭阶段]
下面,我们逐阶段拆解可用的扩展点。
🔧 二、各阶段核心扩展点详解(按执行顺序)
阶段 1️⃣:容器刷新前 ------ 修改环境或 Bean 定义
适用场景:动态注册 Bean、修改配置元数据、注入全局属性。
✅ BeanFactoryPostProcessor
- 作用 :在 Bean 实例化前,修改
BeanDefinition。 - 典型用法:
@ConfigurationProperties绑定;- MyBatis 的
MapperScannerRegistrar动态注册 Mapper 接口为 Bean; - 自定义注解处理器,生成代理 Bean。
java
public class MyCustomBeanRegistrar implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 手动注册 BeanDefinition
BeanDefinitionBuilder builder =
BeanDefinitionBuilder.genericBeanDefinition(MyService.class);
beanFactory.registerBeanDefinition("myService", builder.getBeanDefinition());
}
}
💡 这是唯一能安全修改 Bean 定义的扩展点。
阶段 2️⃣:Bean 初始化前后 ------ 增强或代理目标对象
适用场景:AOP、事务、注入上下文、验证等。
✅ BeanPostProcessor
-
作用:在 Bean 初始化前后进行拦截和增强。
-
两个关键方法
:
postProcessBeforeInitialization:@PostConstruct之前;postProcessAfterInitialization:@PostConstruct之后,返回最终 Bean(可替换为代理)。
java
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof MyCustomComponent) {
return Proxy.newProxyInstance(...); // 返回代理对象
}
return bean;
}
}
🌰 Spring AOP、
@Transactional、@Async全靠它!
阶段 3️⃣:所有非懒加载单例 Bean 初始化完成
适用场景:批量扫描已注册的组件(如 Listener、Handler),并启动底层客户端。
✅ SmartInitializingSingleton
- 作用:当所有单例 Bean 就绪后,执行一次性聚合操作。
- 为什么重要 ? 此时可以安全地通过
beanFactory.getBeansWithAnnotation(...)获取完整组件列表。
java
@Component
public class ConsumerRegistry implements SmartInitializingSingleton {
@Override
public void afterSingletonsInstantiated() {
// 扫描所有 @MyMessageListener 的 Bean
Map<String, Object> listeners =
beanFactory.getBeansWithAnnotation(MyMessageListener.class);
// 为每个 listener 创建并启动底层消费者(如 RocketMQ/Kafka)
listeners.values().forEach(this::startConsumer);
}
}
⚠️ 注意:仅适用于单例 Bean,原型 Bean 不在此列。
阶段 4️⃣:容器完全启动后 ------ 执行业务或框架初始化逻辑
适用场景:启动后台线程、预热缓存、发布就绪信号。
✅ ApplicationRunner / CommandLineRunner
-
作用:容器刷新完成后执行逻辑。
-
区别
:
ApplicationRunner接收ApplicationArguments(结构化参数);CommandLineRunner接收原始String[] args。
java
@Component
public class FrameworkReadyRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
// 框架已就绪,可通知监控系统 or 启动健康检查
HealthReporter.reportReady();
}
}
💡 虽然也可用于扫描 Bean,但比
SmartInitializingSingleton更晚,通常用于业务逻辑而非基础设施初始化。
阶段 5️⃣:运行时事件驱动 ------ 响应容器状态变化
适用场景:监听上下文刷新、环境变更等事件。
✅ ApplicationListener<E extends ApplicationEvent>
✅ @EventListener
java
@Component
public class ContextRefreshedHandler {
@EventListener
public void onContextReady(ContextRefreshedEvent event) {
// 等价于容器启动完成
}
}
🔁 与
ApplicationRunner功能重叠,但更灵活(可监听多种事件)。
阶段 6️⃣:容器关闭阶段 ------ 优雅释放资源
适用场景:关闭连接池、停止消费者、清理线程池。
✅ SmartLifecycle
- 作用 :控制组件的启动(
start())和停止(stop())。 - 优势 :支持有序启停 (通过
getPhase()控制顺序)。
java
@Component
public class MyClientLifecycle implements SmartLifecycle {
private volatile boolean running = false;
@Override
public void start() {
// 启动底层客户端(如 KafkaConsumer.poll() 循环)
this.running = true;
}
@Override
public void stop() {
// 优雅关闭
client.close();
this.running = false;
}
@Override
public boolean isRunning() {
return running;
}
}
🛠️ RocketMQ、Kafka Starter 均使用
SmartLifecycle管理消费者生命周期。
✅ DisposableBean / @PreDestroy
- 作用:单个 Bean 销毁前清理资源。
- 适用:轻量级资源释放(如关闭文件句柄)。
🧩 三、框架封装最佳实践组合
| 目标 | 推荐扩展点组合 |
|---|---|
| 动态注册组件(如 Mapper、Listener) | BeanFactoryPostProcessor + 注解扫描 |
| 创建代理或注入上下文 | BeanPostProcessor |
| 批量启动底层客户端 | SmartInitializingSingleton(扫描) + SmartLifecycle(启停) |
| 容器关闭时释放资源 | SmartLifecycle.stop() + @PreDestroy |
| 发布就绪信号 | ApplicationRunner 或 @EventListener(ContextRefreshedEvent.class) |
✅ 真实案例:
- MyBatis-Spring :
BeanFactoryPostProcessor扫描 Mapper;- Spring Kafka :
SmartInitializingSingleton扫描@KafkaListener,SmartLifecycle控制消费者启停;- Dubbo Spring Boot :
ApplicationListener监听上下文刷新后暴露服务。
🔚 总结
Spring Boot 并非"魔法",而是一套精心设计的扩展体系。作为框架开发者,理解并合理使用这些扩展点,是构建高质量 Starter 的关键:
- 早期 (Bean 定义):用
BeanFactoryPostProcessor注册组件; - 中期 (Bean 初始化):用
BeanPostProcessor增强行为; - 就绪期 (单例完成):用
SmartInitializingSingleton聚合启动; - 运行期 :用
SmartLifecycle管理生命周期; - 关闭期:确保资源被优雅释放。
掌握这套扩展模型,你就能像 Spring 官方一样,写出"用户只需加注解,一切自动生效"的优雅框架。