当前位置: 首页 > news >正文

Spring 事件实战及进阶特性

文章目录

      • 一、核心概念与核心组件
        • 1. 核心组件说明
        • 2. 核心设计思想
      • 二、基本使用步骤(Spring Boot 环境)
        • 1. 步骤 1:定义事件(可选,Spring 4.2)
        • 2. 步骤 2:发布事件
        • 3. 步骤 3:监听事件(注解式,推荐)
      • 三、进阶特性(实际开发必备)
        • 1. 同步 vs 异步事件(核心进阶)
          • 异步事件配置步骤:
        • 2. 事件监听顺序
        • 3. 事务绑定事件(@TransactionalEventListener)
        • 4. 条件监听(仅满足条件时执行)
        • 5. 自定义事件广播器
      • 四、实战案例:电商订单事件流
        • 业务场景:
        • 完整代码:
        • 核心优势:
      • 五、常见问题与注意事项

Spring 事件是基于观察者设计模式的轻量级解耦机制,核心作用是分离事件发布者与订阅者,实现模块间无直接依赖的通信(如订单创建后同步发送通知、更新库存等场景)。以下从核心概念、使用步骤、进阶特性、实战案例等维度展开详细介绍:

一、核心概念与核心组件

Spring 事件体系的核心是 4 个组件,遵循 “发布 - 订阅” 模型:

1. 核心组件说明
组件名称作用描述核心接口 / 类
事件(Event)传递的消息载体,包含事件触发的上下文信息(如订单 ID、操作人等)ApplicationEvent(抽象基类)、PayloadApplicationEvent(Spring 4.2 + 内置,无需自定义事件类)
事件发布者(Publisher)触发并发布事件的组件(如订单服务、用户服务)ApplicationEventPublisher(接口)、ApplicationContext(间接实现该接口,可直接注入使用)
事件监听器(Listener)订阅并处理事件的组件(如通知服务、日志服务)ApplicationListener(接口)、@EventListener(注解,Spring 4.2 + 推荐)、@TransactionalEventListener(事务绑定监听)
事件广播器(Multicaster)负责将事件分发到所有订阅的监听器,是事件机制的 “中转站”ApplicationEventMulticaster(核心接口),默认实现SimpleApplicationEventMulticaster
2. 核心设计思想
  • 解耦:发布者无需知道订阅者的存在,订阅者也无需依赖发布者,通过事件间接通信;

  • 可扩展:新增业务逻辑(如订单创建后新增 “积分发放”)时,只需新增监听器,无需修改发布者代码;

  • 同步默认:默认事件是同步执行(发布者阻塞直到所有监听器执行完毕),支持异步配置。

二、基本使用步骤(Spring Boot 环境)

Spring 4.2 + 后简化了事件使用,无需实现接口,注解式监听成为主流,以下是最常用的 “注解式事件” 完整流程:

1. 步骤 1:定义事件(可选,Spring 4.2)
  • 自定义事件需继承ApplicationEvent,封装事件上下文;

  • 若无需自定义事件类,可直接使用 Spring 内置的PayloadApplicationEvent(传递任意类型的 “负载” 数据)。

// 自定义事件(场景:订单创建事件)public class OrderCreatedEvent extends ApplicationEvent {// 事件携带的上下文信息(如订单ID、用户ID、订单金额)private final Long orderId;private final Long userId;private final BigDecimal amount;// 构造方法:参数1为事件源(通常是发布者本身,可传null),后续为自定义上下文public OrderCreatedEvent(Object source, Long orderId, Long userId, BigDecimal amount) {super(source);this.orderId = orderId;this.userId = userId;this.amount = amount;}// getter方法(监听器需要获取上下文)public Long getOrderId() { return orderId; }public Long getUserId() { return userId; }public BigDecimal getAmount() { return amount; }}
2. 步骤 2:发布事件

通过注入ApplicationEventPublisher(或ApplicationContext,因为其实现了该接口)发布事件:

@Servicepublic class OrderService {// 注入事件发布器(Spring自动注入,无需手动配置)@Autowiredprivate ApplicationEventPublisher eventPublisher;// 订单创建业务:创建订单后发布事件@Transactionalpublic void createOrder(OrderDTO orderDTO) {// 1. 核心业务:保存订单到数据库Long orderId = saveOrderToDB(orderDTO); // 模拟保存逻辑// 2. 发布事件:通知其他模块(如通知服务、积分服务)eventPublisher.publishEvent(new OrderCreatedEvent(this, orderId, orderDTO.getUserId(), orderDTO.getAmount()));// (可选)使用内置PayloadApplicationEvent,无需自定义事件类// eventPublisher.publishEvent(//     new PayloadApplicationEvent<>(this, orderDTO) // 直接传递订单DTO作为负载// );}private Long saveOrderToDB(OrderDTO orderDTO) {// 模拟数据库保存逻辑,返回订单IDreturn System.currentTimeMillis();}}
3. 步骤 3:监听事件(注解式,推荐)

使用@EventListener注解标记监听方法,Spring 自动扫描并注册为监听器,无需实现接口:

// 通知服务监听器:订单创建后发送短信@Servicepublic class NotificationListener {@Autowiredprivate SmsService smsService;// 监听OrderCreatedEvent事件@EventListenerpublic void handleOrderCreatedEvent(OrderCreatedEvent event) {// 获取事件上下文Long userId = event.getUserId();Long orderId = event.getOrderId();// 发送短信通知smsService.sendSms(userId, "您的订单" + orderId + "已创建成功,请注意查收!");}// (可选)监听PayloadApplicationEvent(无需自定义事件类)// @EventListener// public void handlePayloadEvent(PayloadApplicationEvent\<OrderDTO> event) {//     OrderDTO orderDTO = event.getPayload();//     smsService.sendSms(orderDTO.getUserId(), "订单创建通知...");// }}// 积分服务监听器:订单创建后增加积分@Servicepublic class PointListener {@Autowiredprivate PointService pointService;// 监听OrderCreatedEvent事件@EventListenerpublic void addPoint(OrderCreatedEvent event) {Long userId = event.getUserId();BigDecimal amount = event.getAmount();// 按订单金额1%增加积分int point = amount.multiply(new BigDecimal("0.01")).intValue();pointService.addPoint(userId, point);}}

三、进阶特性(实际开发必备)

1. 同步 vs 异步事件(核心进阶)
  • 默认同步:发布者发布事件后,会阻塞直到所有监听器执行完毕(适用于需要监听器执行结果的场景);

  • 异步事件:发布者无需等待监听器执行,直接返回,提高性能(适用于通知、日志等非核心业务)。

异步事件配置步骤:
  1. 启动类添加@EnableAsync开启异步支持;

  2. 监听器方法添加@Async注解;

  3. (可选)自定义线程池(避免使用默认简单线程池)。

// 1. 启动类开启异步@SpringBootApplication@EnableAsync // 关键:开启Spring异步支持public class Application {public static void main(String\[] args) {SpringApplication.run(Application.class, args);}// 2. 自定义线程池(推荐,避免默认线程池的性能问题)@Beanpublic Executor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5); // 核心线程数executor.setMaxPoolSize(10); // 最大线程数executor.setQueueCapacity(20); // 队列容量executor.setThreadNamePrefix("SpringEvent-"); // 线程名前缀executor.initialize();return executor;}}// 3. 监听器方法添加@Async,变为异步执行@Servicepublic class NotificationListener {@Async // 关键:标记为异步监听器@EventListenerpublic void handleOrderCreatedEvent(OrderCreatedEvent event) {// 异步执行:发布者无需等待,直接返回System.out.println("异步发送短信,当前线程:" + Thread.currentThread().getName());smsService.sendSms(event.getUserId(), "订单创建通知...");}}
2. 事件监听顺序

当多个监听器监听同一个事件时,可通过@Order注解指定执行顺序(值越小,优先级越高):

@Servicepublic class LogListener {// 顺序1:最先执行(记录订单创建开始日志)@Order(1)@EventListenerpublic void logStart(OrderCreatedEvent event) {System.out.println("订单" + event.getOrderId() + "创建事件开始处理");}}@Servicepublic class NotificationListener {// 顺序2:中间执行(发送短信)@Order(2)@Async@EventListenerpublic void handleOrderCreatedEvent(OrderCreatedEvent event) {smsService.sendSms(event.getUserId(), "订单创建通知...");}}@Servicepublic class PointListener {// 顺序3:最后执行(增加积分)@Order(3)@EventListenerpublic void addPoint(OrderCreatedEvent event) {pointService.addPoint(event.getUserId(), ...);}}
3. 事务绑定事件(@TransactionalEventListener)

场景:订单创建的事务提交后,才执行监听器(避免事务回滚导致的通知 / 积分错误)。

核心:@TransactionalEventListener可指定事件触发时机(事务提交后、回滚后、完成后等)。

@Servicepublic class NotificationListener {// 事务提交后才执行该监听器@TransactionalEventListener(phase = TransactionPhase.AFTER\_COMMIT)public void handleOrderCreatedEvent(OrderCreatedEvent event) {// 只有当createOrder方法的事务提交成功后,才发送短信smsService.sendSms(event.getUserId(), "订单创建通知...");}}

TransactionPhase枚举值说明:

  • AFTER_COMMIT:事务提交后(默认,最常用);

  • AFTER_ROLLBACK:事务回滚后;

  • AFTER_COMPLETION:事务完成后(无论提交还是回滚);

  • BEFORE_COMMIT:事务提交前。

4. 条件监听(仅满足条件时执行)

通过@ConditionalOnExpression或方法参数条件,实现 “特定场景才触发监听器”:

@Servicepublic class PointListener {// 条件:订单金额>=100元才增加积分@EventListener@ConditionalOnExpression("#event.amount.compareTo(new BigDecimal('100')) >= 0")public void addPoint(OrderCreatedEvent event) {Long userId = event.getUserId();int point = event.getAmount().multiply(new BigDecimal("0.01")).intValue();pointService.addPoint(userId, point);}}
5. 自定义事件广播器

默认广播器是SimpleApplicationEventMulticaster,可自定义广播器实现特殊逻辑(如事件过滤、自定义线程池):

@Configurationpublic class EventConfig {// 自定义事件广播器@Beanpublic ApplicationEventMulticaster applicationEventMulticaster() {SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();// 绑定自定义线程池(异步事件使用)multicaster.setTaskExecutor(taskExecutor());// (可选)设置事件异常处理器(默认监听器抛出异常会中断后续执行)multicaster.setErrorHandler(e -> {System.err.println("监听器执行失败:" + e.getMessage());});return multicaster;}// 自定义线程池@Beanpublic Executor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(20);executor.initialize();return executor;}}

四、实战案例:电商订单事件流

以电商订单创建为例,展示 Spring 事件如何解耦多个模块:

业务场景:

订单创建后需执行 3 个操作:1. 发送短信通知;2. 增加用户积分;3. 记录操作日志。通过事件机制解耦,每个操作作为独立监听器。

完整代码:
  1. 订单事件类(OrderCreatedEvent):同 “基本使用步骤 1”;

  2. 订单服务(OrderService):同 “基本使用步骤 2”;

  3. 3 个监听器(通知、积分、日志):

// 1. 短信通知监听器(异步+事务提交后执行)@Servicepublic class SmsListener {@Autowiredprivate SmsService smsService;@Async@TransactionalEventListener(phase = TransactionPhase.AFTER\_COMMIT)public void sendOrderSms(OrderCreatedEvent event) {smsService.sendSms(event.getUserId(), "订单" + event.getOrderId() + "创建成功!");}}// 2. 积分监听器(条件触发:金额>=100元)@Servicepublic class PointListener {@Autowiredprivate PointService pointService;@TransactionalEventListener(phase = TransactionPhase.AFTER\_COMMIT)@ConditionalOnExpression("#event.amount.compareTo(new BigDecimal('100')) >= 0")public void addOrderPoint(OrderCreatedEvent event) {int point = event.getAmount().multiply(new BigDecimal("0.01")).intValue();pointService.addPoint(event.getUserId(), point);}}// 3. 日志监听器(同步执行,优先记录)@Servicepublic class LogListener {@Autowiredprivate OperationLogService logService;@Order(1)@TransactionalEventListener(phase = TransactionPhase.AFTER\_COMMIT)public void recordOrderLog(OrderCreatedEvent event) {OperationLog log = new OperationLog();log.setUserId(event.getUserId());log.setBusinessType("订单创建");log.setBusinessId(event.getOrderId().toString());log.setCreateTime(new Date());logService.save(log);}}
核心优势:
  • 解耦:订单服务无需依赖短信、积分、日志服务,后续新增 “订单推送” 功能,只需新增监听器;

  • 可维护:每个业务逻辑独立,修改短信发送逻辑不影响订单核心业务;

  • 可扩展:异步事件提高订单创建接口的响应速度,避免因短信发送超时阻塞订单流程。

五、常见问题与注意事项

  1. 异步事件的事务问题:异步监听器无法共享发布者的事务,若需事务一致性,需使用@TransactionalEventListener绑定事务阶段;

  2. 监听器线程安全:默认监听器是单例,若监听器有成员变量,需保证线程安全(如使用ThreadLocal或无状态设计);

  3. 事件泛滥:避免定义过多细粒度事件,可按业务域合并(如 “订单事件” 包含创建、支付、取消等子类型);

  4. 异常处理:同步事件中,某个监听器抛出异常会中断后续监听器执行,可通过自定义ErrorHandler处理;

  5. Spring 版本差异@EventListener是 Spring 4.2 + 新增,若使用旧版本需实现ApplicationListener接口。

http://www.dtcms.com/a/541321.html

相关文章:

  • Three.js 核心技术:相机(正交 / 透视)、动画与资源加载、音视频播放、事件绑定等解析
  • 搭建公司内部网站网络营销方案的制定
  • centos yum源和epel源更换
  • 西宁平台网站建设杭州商城网站建设
  • 2.3、智能入侵检测:基于机器学习的网络流量异常发现
  • DDD本质论:从哲学到数学,再到工程实践的完整指南之实践篇
  • 中国制造网建站陕西省交通建设集团西长分公司网站
  • MFC 使用自定义光标
  • LeetCode 79. 单词搜索
  • 网站建设维护需要懂哪些知识漂亮网页模板
  • 大模型框架选型:LangChain 与 LlamaIndex、Haystack 的核心差异对比
  • 关注公众号平台seo案例视频教程
  • SPL量化工作台使用教程-1-数据和画图
  • 【QT】窗口
  • 脑科学支持的Python学习法:每天2小时碎片化训练,用‘神经可塑性’打败拖延症“
  • 长春网站业务哪个公司好网页设计师女生工资
  • 南昌做网站开发的公司有哪些竞价推广论坛
  • 行业首发!Spring AI Alibaba + Nacos 支持分布式 Multi-Agent 构建
  • 海口建设网站建立网站需要钱吗
  • Linux上的exec函数族详解
  • 产品推荐|千眼狼全新第二代背照式制冷sCMOS相机上市,再次刷新灵敏度和噪声极限
  • 常见协议格式
  • 境外网站可以备案吗长沙网站排名优化费用
  • h5游戏免费下载:上山打老虎
  • 力扣面试经典150题打卡
  • 网站设计就业压力官方网站开发招标须知
  • Android开发常见报错及解决方法(详细版)
  • 做网站内容火星人网页设计培训
  • 免费微网站_自助建站海外直播tiktok
  • 浔川社团总访问量超 13 万:数据见证成长,热爱铸就辉煌