乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • 第1章 Spring概述与IoC容器

    • Spring概述与IoC容器
    • Spring Framework 概述
    • IoC 与 DI 核心概念
    • @Configuration 详解
    • @Component 详解
    • @ComponentScan 详解
    • @Import 详解
    • @Profile 详解
    • @PropertySource 详解
    • @Service 详解
    • @Repository 详解
  • 第2章 Bean的定义与依赖注入

    • Bean的定义与依赖注入
    • @Bean 详解
    • @Autowired 详解
    • @Qualifier 详解
    • @Primary 详解
    • @Resource 详解
    • @Inject 详解
    • @Named 详解
    • @Value 详解
    • @Scope 详解
    • @Lazy 详解
  • 第3章 Bean生命周期与作用域

    • Bean生命周期与作用域
    • Bean生命周期概述
    • @PostConstruct
    • @PreDestroy
    • InitializingBean
    • DisposableBean
    • BeanPostProcessor
    • BeanFactoryPostProcessor
  • 第4章 AOP面向切面编程

    • AOP面向切面编程
    • AOP核心概念
    • @EnableAspectJAutoProxy
    • @Aspect
    • @Pointcut
    • @Before
    • @After
    • @AfterReturning
    • @AfterThrowing
    • @Around
  • 第5章 数据访问与事务管理

    • 数据访问与事务管理
    • 数据访问概述
    • @EnableTransactionManagement
    • @Transactional
    • @Transactional 的传播行为
    • @Transactional 的隔离级别
    • @Transactional 的回滚规则
    • @Transactional 的超时与只读属性
    • @TransactionalEventListener
  • 第6章 Spring Boot自动配置基础

    • Spring Boot自动配置基础
    • @SpringBootApplication 注解
    • @EnableAutoConfiguration 注解
    • @ConfigurationProperties 注解
    • @ConditionalOnClass 注解
    • @ConditionalOnMissingBean 注解
    • @ConditionalOnProperty 注解
  • 第7章 从容器到Web: Spring MVC导引

    • Spring MVC 导引
  • 第8章 扩展阅读

    • 扩展阅读
    • Spring 事件机制 — ApplicationEvent / ApplicationListener
    • @EventListener
    • SpEL — Spring 表达式语言
    • 校验 Validation — JSR-303 / JSR-380 Bean Validation
    • 类型转换与数据绑定 — Converter / DataBinder
  • 附录

    • Spring Framework 专业术语
    • Spring 核心知识点
    • Spring 面试高频考点
    • Spring 核心注解速查表

@EventListener

一句话定位:@EventListener 是 Spring 4.2 带来的"懒人福音"——不用实现 ApplicationListener 接口,直接在任意 Bean 的方法上贴个注解,就能监听 Spring 容器内的事件广播。


概念说明

@EventListener 是 Spring 对事件监听机制的注解化封装。传统方式需要实现 ApplicationListener<E> 接口,一个类只能监听一种事件。@EventListener 打破了这种限制:

  • 一个类可以监听多种事件
  • 支持 SpEL 条件过滤
  • 支持 异步执行
  • 支持 事务绑定

为什么需要它?

传统接口方式的问题:

  1. 侵入性强:必须实现 Spring 接口,与框架耦合
  2. 一个类一种事件:想监听两种事件?写两个类
  3. 无法条件过滤:所有事件都进 onApplicationEvent,内部再 if-else
  4. 无法直接异步:需要配置 ApplicationEventMulticaster

@EventListener 用声明式注解解决了所有痛点。


使用示例(乐途场景)

基础监听

乐途公司的订单系统,一个类处理所有订单相关事件:

@Component
public class OrderNotificationHandler {

    @EventListener
    public void onOrderCreated(OrderCreatedEvent event) {
        System.out.printf("[通知] 订单 %d 已创建,给用户 %d 发站内信%n",
            event.getOrderId(), event.getUserId());
    }

    @EventListener
    public void onOrderPaid(OrderPaidEvent event) {
        System.out.printf("[通知] 订单 %d 已支付 %.2f 元,准备发货%n",
            event.getOrderId(), event.getAmount());
    }

    @EventListener
    public void onOrderShipped(OrderShippedEvent event) {
        System.out.printf("[通知] 订单 %d 已发货,物流单号 %s%n",
            event.getOrderId(), event.getTrackingNumber());
    }
}

SpEL 条件过滤

乐途公司的大单需要运营高英特别关注:

@Component
public class BigOrderAlertHandler {

    // 只监听金额 > 10000 的订单
    @EventListener(condition = "#event.amount > 10000")
    public void alertBigOrder(OrderPaidEvent event) {
        System.out.printf("[运营警报] 大单!订单 %d,金额 %.2f,通知高英跟进%n",
            event.getOrderId(), event.getAmount());
    }

    // 只监听使用支付宝支付的订单
    @EventListener(condition = "#event.paymentMethod == 'ALIPAY'")
    public void alipayPromotion(OrderPaidEvent event) {
        System.out.printf("[营销] 支付宝订单 %d,发放红包%n", event.getOrderId());
    }
}

异步监听

短信通知不需要阻塞订单主流程:

@Component
public class AsyncNotificationHandler {

    @Async
    @EventListener
    public void sendSms(OrderCreatedEvent event) {
        // 在独立线程池中执行
        smsService.send(event.getUserId(), "您的订单已提交,订单号:" + event.getOrderId());
    }

    @Async
    @EventListener
    public void sendEmail(OrderPaidEvent event) {
        emailService.sendPaymentConfirmation(event.getOrderId(), event.getAmount());
    }
}

需要先在配置类上标注 @EnableAsync。

事务绑定监听

库存扣减必须在订单事务提交后才执行:

@Component
public class InventoryEventHandler {

    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void deductInventory(OrderCreatedEvent event) {
        // 事务已提交,安全地扣减库存
        inventoryService.deduct(event.getProductId(), event.getQuantity());
    }

    @TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
    public void releaseInventory(OrderCreatedEvent event) {
        // 事务回滚,释放预留库存
        inventoryService.release(event.getProductId(), event.getQuantity());
    }
}

监听多个事件类型

@Component
public class AuditLogHandler {

    // 一个方法监听多种事件
    @EventListener({OrderCreatedEvent.class, OrderPaidEvent.class, OrderShippedEvent.class})
    public void recordAudit(AbstractOrderEvent event) {
        auditLogService.record(event.getOrderId(), event.getClass().getSimpleName());
    }
}

核心属性

属性说明
value / classes指定监听的事件类型,可省略(由方法参数类型推断)
conditionSpEL 表达式,只有结果为 true 时才触发
id监听器标识,可用于程序化移除

注意事项

注意点说明
方法参数即事件类型方法有且仅有一个参数,类型即为监听的事件类型。如果监听多种事件,参数用共同父类
返回值如果方法返回值不是 void,Spring 会把它当作新事件再次发布
异常处理同步监听器抛异常会中断后续监听器。建议内部 try-catch,或用异步隔离
与 @Transactional 的关系@EventListener 默认参与发布者的事务。如需独立事务,方法上加 @Transactional(propagation = REQUIRES_NEW)
泛型事件Spring 4.2+ 支持发布任意对象(不强制继承 ApplicationEvent),@EventListener 按参数类型匹配

常见面试题

Q1:@EventListener 和 ApplicationListener 接口方式有什么区别?

@EventListener 更灵活:一个类可监听多种事件、支持 SpEL 条件过滤、支持异步和事务绑定、无需实现接口。ApplicationListener 是标准接口,类型安全但功能受限。现代项目推荐 @EventListener。

Q2:@EventListener 方法的返回值有什么用?

如果方法返回值不是 void,Spring 会将其包装为 PayloadApplicationEvent 再次发布到容器中。这可以实现事件链:A 事件触发 → 监听器处理 → 返回 B 事件 → 另一个监听器处理 B。

Q3:@TransactionalEventListener 和 @EventListener + @Transactional 有什么区别?

@TransactionalEventListener 专门用于绑定事务阶段(AFTER_COMMIT / AFTER_ROLLBACK),确保在正确的事务时机执行。@EventListener + @Transactional 只是让监听器在独立事务中运行,不绑定发布者的事务阶段。

Q4:为什么我的 @Async @EventListener 没触发?

可能原因:① 没有 @EnableAsync;② 异步线程池已满;③ 监听器方法抛异常被吞掉;④ 事件在事务中发布但监听器是 AFTER_COMMIT,而事务已回滚。

上一页
Spring 事件机制 — ApplicationEvent / ApplicationListener
下一页
SpEL — Spring 表达式语言