在 Spring Boot 中,ApplicationListener 和 SpringApplicationRunListener 是两个作用层级、加载时机和使用场景都截然不同的监听器。
它们最核心的区别在于:
ApplicationListener 是 Spring 容器内的"业务事件监听器",
SpringApplicationRunListener 是 Spring Boot 启动流程的"生命周期监听器"。
核心区别概述
这两个接口服务于不同的阶段和目的:
ApplicationListener:关注的是 Spring 容器内部 发生的事件,主要用于业务逻辑 或通用服务在容器生命周期不同阶段(包括应用启动阶段,跟事件监听类型有关)的操作。SpringApplicationRunListener:关注的是 Spring Boot 应用启动过程本身 的关键节点,主要用于框架层面 或基础设施 在容器初始化之前 或期间的操作。
详细对比
-
所属框架与作用域
ApplicationListener:- 属于 Spring Framework。
- 作用域是整个 Spring 应用上下文(
ApplicationContext)的生命周期。容器启动后,它可以监听容器内发布的各种事件。
SpringApplicationRunListener:- 属于 Spring Boot。
- 作用域仅限于
SpringApplication.run(...)方法的执行过程。它监听的是应用启动流程中的特定阶段。
-
加载时机与管理方式
ApplicationListener:- 作为 Spring Bean 被管理。
- 加载时机:在 Spring 容器启动过程中,随着其他 Bean 一起被创建和初始化。
- 注册方式:可以通过
@Component、@Bean注解定义,或者通过SpringApplication.addListeners(...)方法添加。 - 支持依赖注入 :可以像普通 Bean 一样使用
@Autowired、@Value等。
SpringApplicationRunListener:- 不由 Spring 容器管理。
- 加载时机:非常早 ,在 Spring 容器创建之前。
- 注册方式:必须通过在
META-INF/spring.factories文件中配置org.springframework.boot.SpringApplicationRunListener键来声明实现类的全限定名(使用 SPI 机制)。 - 不支持依赖注入 :因为它加载时 Spring 容器还不存在,无法注入其他 Bean 或读取
@Value配置。只能通过构造参数(接收SpringApplication实例和String[] args)或直接访问环境等方式获取信息。
-
监听的事件类型
-
ApplicationListener:- 监听
ApplicationEvent及其子类。 - 事件来源广泛:
- Spring 内置事件 :如
ContextRefreshedEvent(容器刷新完成)、ContextClosedEvent(容器关闭)。 - Spring Boot 启动事件 :如
ApplicationStartedEvent、ApplicationReadyEvent(注意:这些事件通常是由EventPublishingRunListener转发的SpringApplicationRunListener事件,即可以监听spring boot 的启动生命周期,使用形式ApplicationListener<ApplicationStartedEvent>)。 - 自定义业务事件 :开发者可以定义自己的事件类(如
OrderPaidEvent)并发布。 - 实现方式:使用@EventListener注解简化监听,或者实现 ApplicationListener<自定义事件>,在 onApplicationEvent 中编写处理逻辑。
- Spring 内置事件 :如
- 监听
-
SpringApplicationRunListener:- 监听的是 Spring Boot 启动流程中的固定阶段 ,每个阶段对应接口中的一个方法回调:
starting:run()方法刚开始执行。environmentPrepared:Environment准备好,但ApplicationContext还未创建。contextPrepared:ApplicationContext创建好,但在加载 Bean 定义之前。contextLoaded:ApplicationContext加载完 Bean 定义,但在刷新容器之前。started:ApplicationContext已刷新,应用已启动,但CommandLineRunner/ApplicationRunner还未执行。running:所有Runner已执行完毕,run()方法即将结束。failed:启动过程中发生异常。
- 监听的是 Spring Boot 启动流程中的固定阶段 ,每个阶段对应接口中的一个方法回调:
-
-
典型使用场景
ApplicationListener:- 业务逻辑解耦 :监听自定义业务事件(如
UserRegisteredEvent),触发发送邮件、初始化用户信息等操作。 - 容器生命周期钩子 :监听
ContextRefreshedEvent进行缓存预热、初始化全局服务;监听ApplicationReadyEvent执行最终检查或通知外部系统应用已就绪。 - 响应内置事件 :监听
ContextClosedEvent执行资源清理。
- 业务逻辑解耦 :监听自定义业务事件(如
SpringApplicationRunListener:- 极早期配置处理 :在
environmentPrepared阶段从远程配置中心(如 Nacos, Consul)拉取配置,或者对配置文件中的加密属性进行解密。 - 启动过程定制 :在
starting阶段输出自定义 Banner 或启动日志。 - 环境检查与准备 :在
environmentPrepared阶段验证环境变量或进行必要的系统设置。 - 框架/工具集成 :在容器初始化前(如
contextPrepared或更早)集成 APM 监控探针进行字节码增强。
- 极早期配置处理 :在
两者联系
Spring Boot 提供了一个关键的 SpringApplicationRunListener 实现:EventPublishingRunListener。它的作用是将 SpringApplicationRunListener 接收到的各个阶段回调(如 starting, environmentPrepared)转换并发布 成对应的 ApplicationEvent (如 ApplicationStartingEvent, ApplicationEnvironmentPreparedEvent)。这些事件随后会被广播给所有注册的 ApplicationListener。
因此,ApplicationListener 可以间接感知到 Spring Boot 的启动过程(通过监听 ApplicationStartingEvent, ApplicationEnvironmentPreparedEvent 等事件),而 SpringApplicationRunListener 提供了更底层、更早期的介入点。EventPublishingRunListener 充当了桥梁角色。
总结对比表
| 特性 | ApplicationListener |
SpringApplicationRunListener |
|---|---|---|
| 所属框架 | Spring Framework | Spring Boot |
| 作用域 | Spring 容器生命周期 | SpringApplication.run() 执行过程 |
| 管理方式 | Spring 容器管理的 Bean | SPI 加载,不受容器管理 |
| 依赖注入支持 | 支持 (@Autowired, @Value) |
不支持 |
| 注册方式 | @Component, @Bean, addListeners() |
META-INF/spring.factories (SPI) |
| 事件/阶段 | ApplicationEvent 及其子类 |
启动流程的固定方法回调 (starting 等) |
| 典型场景 | 业务解耦、缓存预热、处理自定义事件 | 启动前配置加载、解密、环境检查、APM 集成 |
| 执行时机 (相对容器) | 容器初始化后 | 容器初始化前 或期间 |
理解这些区别有助于在合适的场景选择正确的扩展点。