ApplicationListener 和 SpringApplicationRunListener 深度解析对比

在 Spring Boot 中,ApplicationListener 和 SpringApplicationRunListener 是两个作用层级、加载时机和使用场景都截然不同的监听器。

它们最核心的区别在于:‌

ApplicationListener 是 Spring 容器内的"业务事件监听器",

SpringApplicationRunListener 是 Spring Boot 启动流程的"生命周期监听器"。

核心区别概述

这两个接口服务于不同的阶段和目的:

  • ApplicationListener :关注的是 Spring 容器内部 发生的事件,主要用于业务逻辑通用服务在容器生命周期不同阶段(包括应用启动阶段,跟事件监听类型有关)的操作。
  • SpringApplicationRunListener :关注的是 Spring Boot 应用启动过程本身 的关键节点,主要用于框架层面基础设施 在容器初始化之前期间的操作。

详细对比

  1. 所属框架与作用域

    • ApplicationListener
      • 属于 Spring Framework
      • 作用域是整个 Spring 应用上下文(ApplicationContext)的生命周期。容器启动后,它可以监听容器内发布的各种事件。
    • SpringApplicationRunListener
      • 属于 Spring Boot
      • 作用域仅限于 SpringApplication.run(...) 方法的执行过程。它监听的是应用启动流程中的特定阶段。
  2. 加载时机与管理方式

    • 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)或直接访问环境等方式获取信息。
  3. 监听的事件类型

    • ApplicationListener

      • 监听 ApplicationEvent 及其子类
      • 事件来源广泛:
        • Spring 内置事件 :如 ContextRefreshedEvent(容器刷新完成)、ContextClosedEvent(容器关闭)。
        • Spring Boot 启动事件 :如 ApplicationStartedEventApplicationReadyEvent(注意:这些事件通常是由 EventPublishingRunListener 转发的 SpringApplicationRunListener 事件,即可以监听spring boot 的启动生命周期,使用形式ApplicationListener<ApplicationStartedEvent>)。
        • 自定义业务事件 :开发者可以定义自己的事件类(如 OrderPaidEvent)并发布。
        • 实现方式:使用@EventListener注解简化监听,或者实现 ApplicationListener<自定义事件>,在 onApplicationEvent 中编写处理逻辑。
    • SpringApplicationRunListener

      • 监听的是 Spring Boot 启动流程中的固定阶段 ,每个阶段对应接口中的一个方法回调:
        • startingrun() 方法刚开始执行。
        • environmentPreparedEnvironment 准备好,但 ApplicationContext 还未创建。
        • contextPreparedApplicationContext 创建好,但在加载 Bean 定义之前。
        • contextLoadedApplicationContext 加载完 Bean 定义,但在刷新容器之前。
        • startedApplicationContext 已刷新,应用已启动,但 CommandLineRunner/ApplicationRunner 还未执行。
        • running:所有 Runner 已执行完毕,run() 方法即将结束。
        • failed:启动过程中发生异常。
  4. 典型使用场景

    • 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 集成
执行时机 (相对容器) 容器初始化 容器初始化期间

理解这些区别有助于在合适的场景选择正确的扩展点。

相关推荐
ch.ju1 小时前
Java Programming Chapter 2-Recursion of function
java·开发语言
yuanpan1 小时前
Python + matplotlib 数据可视化入门教程:折线图、柱状图、饼图与 Excel 绘图
开发语言·python·opencv
Highcharts.js1 小时前
Highcharts 助力医疗与生命科学研究的数据分析|让医学数据轻易呈现
开发语言·信息可视化·highcharts·实战代码·响应式图表
铁皮哥1 小时前
【后端开发】RabbitMQ、RocketMQ、Kafka 怎么选?我从业务场景重新梳理了一遍
java·linux·数据库·分布式·kafka·rabbitmq·rocketmq
AC赳赳老秦1 小时前
数据库操作自动化:用 OpenClaw 对接 Navicat/DBeaver,实现数据备份、脱敏、日常操作自动化
java·运维·数据库·python·oracle·自动化·openclaw
程序员小白条1 小时前
AI 编程辅助,从入门到真香
java·开发语言·数据库·人工智能·面试·职场和发展
ErizJ1 小时前
Go|腾讯面经总结
开发语言·后端·golang
MATLAB代码顾问1 小时前
差分进化算法(DE)原理与Python实现
开发语言·python·算法
步达硬件1 小时前
【MATLAB】生成视频code(用于显示器画质测试)
开发语言·matlab·音视频