【各大框架如何监听 Spring Boot 八大启动事件(源码级详细讲解)】
各大框架如何监听Spring Boot八大启动事件(源码级详细讲解)
结合上一轮8个启动事件顺序,按基础内置框架 → Spring Cloud微服务生态 → 中间件ORM/缓存/消息 → 监控运维框架分类,逐个说明每个框架监听哪个事件、做了什么核心逻辑、扩展原理。
一、Spring Boot 框架自身内置监听器(最底层)
Spring Boot 原生自带多个SPI加载的监听器,全程驱动启动流程,全部基于ApplicationListener实现,SPI文件META-INF/spring.factories自动注册。
1. ApplicationStartingEvent(启动最开始)
监听框架:LoggingApplicationListener
- 核心行为:
- 扫描classpath自动识别日志实现(优先级Logback > Log4j2 > JUL)
- 提前初始化日志上下文,加载
logback-spring.xml/log4j2.xml - 打印启动Banner、启动参数日志
- 意义:容器还没创建,必须在最早阶段初始化日志,否则后续启动无输出日志
FileEncodingApplicationListener
- 校验系统文件编码,强制UTF-8,编码异常直接阻断启动。
2. ApplicationEnvironmentPreparedEvent(环境配置就绪)
这是监听数量最多的事件,几乎所有配置类框架都卡在这一步:
- ConfigFileApplicationListener(SpringBoot核心配置加载器)
- 加载
application.yml/application.properties、多环境application-dev.yml - 把配置注入Environment属性源,是所有配置的入口
- 加载
- EnvironmentPostProcessorApplicationListener
- 统一调度所有
EnvironmentPostProcessor后置处理器 - Nacos、Spring Cloud Config、Apollo配置中心全部通过它扩展拉远程配置
- 统一调度所有
- BootstrapApplicationListener(Spring Cloud专属内置)
- Spring Cloud最优先级监听器,加载
bootstrap.yml(优先级高于application) - 启动Bootstrap上下文,提前初始化配置中心客户端,保证远程配置优先加载本地配置
- Spring Cloud最优先级监听器,加载
- BackgroundPreinitializer
后台异步预初始化Jackson、ConversionService、字符转换器,缩短主线程启动耗时。
3. ApplicationContextInitializedEvent(上下文创建完毕,无Bean)
SpringBoot内置无大量业务监听器,主要留给三方扩展:
- 允许三方注册
ApplicationContextInitializer,修改上下文参数、注册BeanDefinition扫描规则 - 例如:自定义包扫描、动态注册配置类、设置ApplicationContext环境变量
4. ApplicationPreparedEvent(Bean定义加载完成,未实例化)
- ConfigFileApplicationListener二次处理:绑定
@ConfigurationProperties配置类 - 配置中心补充:把远程配置二次合并到上下文属性源
- 三方框架:MyBatis、Druid在此阶段注册Bean定义、解析mapper扫描路径
5. ContextRefreshedEvent(Spring原生事件,容器刷新完成,单例Bean全部实例化)
- Spring上下文核心刷新完成事件,所有Bean已经
@Autowired、@PostConstruct执行完毕 - 内置:PropertySourcesPlaceholderConfigurer完成占位符
${xxx}替换 - 所有中间件连接池、数据库连接、Redis客户端全部初始化完成
6. ApplicationStartedEvent(容器刷新后,Runner执行前)
SpringBoot内置:启动计时标记、生命周期回调触发;
三方用来做轻量初始化,不会阻塞请求就绪。
7. ApplicationReadyEvent(应用完全就绪,Tomcat启动、可接收请求)
SpringBoot内置:打印Started XApplication in X seconds启动成功日志;
微服务注册、监控上报、缓存预热全部集中在此。
8. ApplicationFailedEvent(启动异常)
- LoggingApplicationListener:打印完整异常堆栈日志
- 所有三方框架:关闭已创建的资源(数据库连接、Nacos长连接、线程池)
- 扩展:发送失败告警、记录启动失败埋点
二、Spring Cloud 微服务全家桶(高频使用启动事件)
1. Nacos(配置中心+注册中心)
(1)配置模块:监听ApplicationEnvironmentPreparedEvent
- 实现类:
NacosConfigEnvironmentProcessor被EnvironmentPostProcessorApplicationListener调度执行 - 逻辑:
- 读取bootstrap/application里
spring.cloud.nacos.config地址、分组、命名空间 - 远程拉取配置,把Nacos配置塞入Environment属性源,优先级高于本地yml
- 开启配置监听长连接,后续热更新
- 读取bootstrap/application里
(2)注册模块:监听ApplicationReadyEvent
- 实现:
NacosAutoServiceRegistration - 逻辑:必须等Tomcat端口启动、应用完全就绪后,才向Nacos注册实例(状态UP);如果提前注册,网关会转发空请求到未就绪服务
2. Eureka(Netflix注册中心)
- 注册逻辑:
EurekaAutoServiceRegistration监听ApplicationReadyEvent - 原理:容器刷新、Tomcat启动完毕后,才调用Eureka Client发起注册;启动失败时监听
ApplicationFailedEvent取消注册/清理实例
3. Spring Cloud Config 配置中心
BootstrapApplicationListener在ApplicationEnvironmentPreparedEvent阶段创建bootstrap上下文,拉取Git远程配置,逻辑和Nacos一致
4. OpenFeign / LoadBalancer
ContextRefreshedEvent:Bean刷新完成后,扫描@FeignClient接口,动态生成代理BeanApplicationReadyEvent:初始化负载均衡节点列表、预热服务实例缓存
5. Spring Cloud Gateway
ContextRefreshedEvent:加载路由配置、实例化Filter、PredicateApplicationReadyEvent:启动Netty服务,注册网关实例到注册中心
6. Sentinel 流量防护
ApplicationEnvironmentPreparedEvent:读取sentinel配置、控制台地址ContextRefreshedEvent:初始化流量规则、埋点切面、线程池ApplicationReadyEvent:连接Sentinel控制台上报应用状态
7. Spring Cloud Bus(配置总线)
ApplicationReadyEvent:连接RabbitMQ/Kafka,订阅配置刷新Topic,监听全局配置变更
三、ORM、数据库、连接池框架
1. MyBatis / MyBatis-Plus
- ApplicationPreparedEvent:
MybatisAutoConfiguration读取mybatis.mapper-locations、typeAliases,注册Mapper扫描BeanDefinition - ContextRefreshedEvent:
实例化SqlSessionFactory、Mapper代理对象、分页插件、全局拦截器;此时数据源连接池已经就绪 - 不会用ApplicationReadyEvent:数据库连接必须在Bean阶段就绪,否则业务Bean注入Mapper报错
2. Druid 数据库连接池
ApplicationEnvironmentPreparedEvent:解析druid连接地址、账号、监控配置ContextRefreshedEvent:初始化连接池、创建监控Servlet、Wall防火墙配置
3. Sharding-JDBC 分库分表
ApplicationEnvironmentPreparedEvent:加载分片规则、数据源列表ContextRefreshedEvent:初始化多数据源、SQL解析引擎、分片算法Bean
4. Flyway / Liquibase 数据库版本迁移
- ContextRefreshedEvent是标准监听点:
Bean刷新完成、数据源初始化完毕后,自动执行SQL迁移脚本;
绝对不能放在更早事件(此时数据源还没实例化)
四、缓存、消息中间件
1. Redis(Spring Data Redis / Redisson)
ApplicationEnvironmentPreparedEvent:读取redis地址、密码、集群配置ContextRefreshedEvent:创建Redis连接池、RedissonClient实例、序列化器- 业务扩展常用
ApplicationReadyEvent做缓存预热(框架自身不做,业务自定义监听)
2. RabbitMQ / RocketMQ / Kafka
ApplicationEnvironmentPreparedEvent:解析Broker地址、队列、交换机、消费者组ContextRefreshedEvent:创建连接工厂、生产者实例- ApplicationReadyEvent:启动消费者监听(核心!)
框架设计逻辑:等应用完全能接收HTTP请求后,再开始消费消息;避免服务还没就绪就收到消息导致处理失败、消息堆积
3. XXL-Job 定时任务
ApplicationReadyEvent启动调度器、注册执行器到调度中心;
如果在ContextRefreshedEvent启动任务,可能Bean还没完全初始化,任务执行空指针。
五、监控、运维、安全框架
1. Spring Boot Actuator 健康监控
ContextRefreshedEvent:注册所有健康指标(DB、Redis、Disk、注册中心)ApplicationReadyEvent:标记健康状态为UP,暴露/actuator端点
2. Prometheus / Micrometer 埋点监控
ContextRefreshedEvent:初始化指标Registry、Meter埋点ApplicationReadyEvent:启动监控推送线程、上报应用启动耗时
3. Spring Security 安全框架
ContextRefreshedEvent:加载SecurityFilterChain、权限规则、密码编码器、JWT过滤器
4. Apollo 配置中心
同Nacos,ApplicationEnvironmentPreparedEvent阶段拉远程配置,通过EnvironmentPostProcessor扩展Environment
六、各个事件的框架使用汇总对照表
| 启动事件 | 主要使用框架 & 核心作用 |
|---|---|
| ApplicationStartingEvent | SpringBoot Logging、编码校验;仅极早期底层初始化 |
| ApplicationEnvironmentPreparedEvent | Nacos/Config/Apollo、Bootstrap上下文、配置文件加载、日志配置、Druid分片配置 |
| ApplicationContextInitializedEvent | 三方自定义上下文初始化、BeanDefinition预注册 |
| ApplicationPreparedEvent | MyBatis Mapper扫描、配置属性绑定、Bean定义装载 |
| ContextRefreshedEvent | 数据库连接池、Redis、Security、Feign代理、Flyway迁移、所有单例Bean实例化 |
| ApplicationStartedEvent | 轻量状态打点、内部生命周期回调 |
| ApplicationReadyEvent | Nacos/Eureka服务注册、MQ消费者启动、定时任务启动、缓存预热、监控上报、启动成功通知 |
| ApplicationFailedEvent | 全框架资源释放、异常日志打印、失败告警、注册中心下线实例 |
七、框架通用扩展原理(为什么都用这套事件)
- SPI机制:大部分底层监听器在
spring.factories配置,SpringBoot启动自动实例化,不需要@Component; - 时序强依赖:
- 配置类必须早于容器创建 → 绑定EnvironmentPreparedEvent
- Bean实例化必须在ContextRefreshedEvent
- 对外注册、消费必须等服务完全可用 → ApplicationReadyEvent
- 容错隔离:启动失败事件统一回收资源,避免连接泄漏、脏注册实例;
- 扩展一致性:所有三方框架统一接入Spring事件标准,不用各自实现一套启动生命周期。
八、业务开发参考(模仿框架设计规范)
- 配置解密、动态配置 → 监听
ApplicationEnvironmentPreparedEvent - 数据库初始化脚本、自定义Bean装配 →
ContextRefreshedEvent - 服务注册、消息消费、缓存预热、钉钉启动通知 →
ApplicationReadyEvent - 失败告警、资源关闭 →
ApplicationFailedEvent - 极早期启动参数校验 →
ApplicationStartingEvent(必须用addListeners注册,@EventListener抓不到)
代码示例:监听所有事件(可直接复制)
方式 1:使用 @EventListener 注解(最简单)
importorg.springframework.boot.context.event.*;importorg.springframework.context.event.ContextRefreshedEvent;importorg.springframework.context.event.EventListener;importorg.springframework.stereotype.Component;@ComponentpublicclassBootAllEventListener{@EventListener(ApplicationStartingEvent.class)publicvoidonStart(){System.out.println("1. 应用开始启动");}@EventListener(ApplicationEnvironmentPreparedEvent.class)publicvoidonEnvPrepared(){System.out.println("2. 环境配置已加载");}@EventListener(ApplicationContextInitializedEvent.class)publicvoidonContextInit(){System.out.println("3. 容器初始化完成");}@EventListener(ApplicationPreparedEvent.class)publicvoidonContextPrepared(){System.out.println("4. 容器准备完成,Bean未加载");}@EventListener(ContextRefreshedEvent.class)publicvoidonContextRefreshed(){System.out.println("5. 容器刷新完成,Bean已加载");}@EventListener(ApplicationStartedEvent.class)publicvoidonStarted(){System.out.println("6. 应用已启动");}@EventListener(ApplicationReadyEvent.class)publicvoidonReady(){System.out.println("7. 应用就绪,可以接收请求");// 这里写启动后必执行逻辑:服务注册、缓存预热等}@EventListener(ApplicationFailedEvent.class)publicvoidonFailed(){System.err.println("8. 应用启动失败!");}}方式 2:实现 ApplicationListener 接口(早期事件必须用这个)
ApplicationStartingEvent 等早期事件,@EventListener 抓不到,必须用如下方式:
importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.boot.context.event.ApplicationStartingEvent;importorg.springframework.context.ApplicationListener;@SpringBootApplicationpublicclassDemoApplication{publicstaticvoidmain(String[]args){SpringApplicationapp=newSpringApplication(DemoApplication.class);// 注册早期事件监听器app.addListeners((ApplicationListener<ApplicationStartingEvent>)event->{System.out.println("早期事件:应用启动中");});app.run(args);}}