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

Spring发布订阅模式详解

Spring 的发布订阅模式(Publish-Subscribe Pattern)是一种基于事件驱动的设计模式,通过 "事件" 作为中间载体实现组件间的解耦。在这种模式中,"发布者"(Publisher)负责产生事件并发布,"订阅者"(Subscriber)通过订阅特定事件接收通知并处理,两者无需直接依赖,从而降低系统耦合度。

一、核心概念与角色

Spring 的发布订阅模式主要涉及三个核心角色:

  1. 事件(Event)
    事件是发布者与订阅者之间的通信载体,封装了需要传递的数据。在 Spring 中,所有事件都需继承ApplicationEvent(Spring 4.2 + 后可省略继承,直接使用普通类作为事件)。

  2. 发布者(Publisher)
    负责创建并发布事件的组件。Spring 中通过ApplicationEventPublisher接口(或其实现类,如ApplicationContext)来发布事件,调用publishEvent()方法即可。

  3. 订阅者(Subscriber)
    负责监听并处理特定事件的组件。Spring 中订阅者可通过实现ApplicationListener接口,或使用@EventListener注解定义事件处理方法。

二、Spring 事件机制的核心组件

1. ApplicationEvent(事件基类)

ApplicationEvent是 Spring 事件的基类,继承自 JDK 的EventObject,包含事件源(source)和事件发生时间(timestamp)。

// Spring内置的ApplicationEvent
public abstract class ApplicationEvent extends EventObject {private final long timestamp; // 事件发生时间public ApplicationEvent(Object source) {super(source);this.timestamp = System.currentTimeMillis();}public final long getTimestamp() {return this.timestamp;}
}

自定义事件示例
通常通过继承ApplicationEvent定义业务事件:

// 自定义用户注册事件
public class UserRegisteredEvent extends ApplicationEvent {private User user; // 事件中携带的用户数据public UserRegisteredEvent(Object source, User user) {super(source);this.user = user;}public User getUser() {return user;}
}

Spring 4.2 + 后支持非继承 ApplicationEvent 的事件,直接使用普通类即可:

// 无需继承ApplicationEvent的事件
public class OrderCreatedEvent {private Order order;// 构造器、getter等
}
2. ApplicationListener(订阅者接口)

ApplicationListener是订阅者的核心接口,用于定义事件处理逻辑,泛型参数指定需要监听的事件类型。

// Spring的事件监听器接口
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {// 事件处理方法,当监听的事件被发布时调用void onApplicationEvent(E event);
}

实现接口的订阅者示例

// 监听UserRegisteredEvent的订阅者(发送欢迎邮件)
@Component
public class WelcomeEmailListener implements ApplicationListener<UserRegisteredEvent> {@Overridepublic void onApplicationEvent(UserRegisteredEvent event) {User user = event.getUser();System.out.println("给用户" + user.getName() + "发送欢迎邮件...");}
}
3. ApplicationEventPublisher(发布者接口)

ApplicationEventPublisher是发布事件的接口,定义了发布事件的方法:

public interface ApplicationEventPublisher {// 发布事件void publishEvent(ApplicationEvent event);// Spring 4.2+新增,支持发布非ApplicationEvent类型的事件void publishEvent(Object event);
}

发布者的实现
Spring 的ApplicationContext(容器本身)实现了ApplicationEventPublisher接口,因此可直接通过容器发布事件。实际开发中,通常通过依赖注入ApplicationEventPublisherApplicationContext来发布事件:

@Service
public class UserService {// 注入事件发布器@Autowiredprivate ApplicationEventPublisher publisher;public void register(User user) {// 1. 执行注册逻辑System.out.println("用户" + user.getName() + "注册成功");// 2. 发布用户注册事件publisher.publishEvent(new UserRegisteredEvent(this, user));}
}

三、注解驱动的事件监听(@EventListener)

Spring 4.2 引入@EventListener注解,无需实现ApplicationListener接口,直接在方法上标注即可定义事件处理逻辑,更简洁灵活。

基本用法
@Component
public class UserEventHandler {// 监听UserRegisteredEvent事件@EventListenerpublic void handleUserRegisteredEvent(UserRegisteredEvent event) {User user = event.getUser();System.out.println("处理用户注册事件:" + user.getName());}// 监听多个事件(方法参数为多个事件类型)@EventListenerpublic void handleMultiEvents(UserRegisteredEvent userEvent, OrderCreatedEvent orderEvent) {// 处理逻辑}
}
条件监听(condition)

通过condition属性指定 SpEL 表达式,满足条件时才执行监听逻辑:

@EventListener(condition = "#event.user.age > 18") // 只处理成年用户的注册事件
public void handleAdultUserRegistered(UserRegisteredEvent event) {// 处理逻辑
}
事件顺序(@Order)

多个监听器监听同一事件时,通过@Order指定执行顺序(值越小越先执行)

@Order(1) // 先执行
@EventListener
public void handleFirst(UserRegisteredEvent event) { ... }@Order(2) // 后执行
@EventListener
public void handleSecond(UserRegisteredEvent event) { ... }

四、异步事件处理

默认情况下,Spring 事件处理是同步的:发布者发布事件后,会等待所有监听器处理完成才继续执行。若需异步处理(不阻塞发布者),可通过以下步骤实现:

  1. 启用异步支持:在配置类上添加@EnableAsync注解。
  2. 标注异步方法:在监听方法上添加@Async注解。

示例:

// 1. 配置类启用异步
@Configuration
@EnableAsync
public class AsyncConfig {// 可选:自定义线程池@Beanpublic Executor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(25);executor.initialize();return executor;}
}// 2. 异步处理事件的监听器
@Component
public class AsyncUserListener {@Async // 异步执行@EventListenerpublic void handleAsync(UserRegisteredEvent event) {System.out.println("异步处理事件:" + Thread.currentThread().getName());// 耗时操作(如发送短信、调用第三方接口等)}
}

五、事务绑定事件(@TransactionalEventListener)

在业务中,常需要在事务完成后(提交 / 回滚)再处理事件(例如:订单事务提交后再发送通知)。Spring 提供@TransactionalEventListener注解,支持绑定事务生命周期。

注解的phase属性指定事务阶段:

  • AFTER_COMMIT:事务提交后(默认)
  • AFTER_ROLLBACK:事务回滚后
  • AFTER_COMPLETION:事务完成后(无论提交还是回滚)
  • BEFORE_COMMIT:事务提交前

示例:

@Service
public class OrderService {@Autowiredprivate ApplicationEventPublisher publisher;@Transactionalpublic void createOrder(Order order) {// 保存订单(事务内操作)orderRepository.save(order);// 发布事件(实际处理会在事务提交后)publisher.publishEvent(new OrderCreatedEvent(order));}
}@Component
public class OrderEventListener {// 订单事务提交后才处理事件@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)public void handleOrderCreated(OrderCreatedEvent event) {System.out.println("订单" + event.getOrder().getId() + "已提交,发送通知...");}
}

六、事件传播机制

Spring 事件具有层次性:监听器可监听父类事件,从而接收所有子类事件。例如:

  • ApplicationEvent是所有事件的父类,监听ApplicationEvent的监听器会接收所有类型的事件。
  • 自定义事件UserEvent的子类UserRegisteredEventUserDeletedEvent,监听UserEvent的监听器会接收这两个子类事件。

七、应用场景

Spring 发布订阅模式适用于以下场景:

  1. 业务解耦:例如用户注册后,需要发送邮件、积分初始化、日志记录等操作,通过事件分离这些逻辑,避免注册服务与其他服务直接耦合。
  2. 异步通知:耗时操作(如短信发送、报表生成)通过异步事件处理,不阻塞主流程。
  3. 状态变更通知:如订单状态变更后,通知库存、支付、物流等相关模块。
  4. 跨组件通信:不同模块(如 Controller、Service、Repository)通过事件交互,无需直接依赖。

总结

Spring 的发布订阅模式基于事件驱动,通过ApplicationEventApplicationListenerApplicationEventPublisher三大组件实现,配合@EventListener@Async@TransactionalEventListener等注解,提供了灵活、解耦的组件通信方式。其核心价值在于降低组件间耦合度,提高系统的可扩展性和可维护性。

http://www.xdnf.cn/news/18533.html

相关文章:

  • Python 调用 sora_image模型 API 实现图片生成与垫图
  • 【论文】Zotero文献管理
  • 为什么应用会突然耗尽所有数据库连接
  • 轮廓检测技术不仅能精确计算图像中的轮廓数量,还能完整记录每个轮廓包含的所有像素点坐标
  • 【0基础3ds Max】捕捉工具详解
  • 宋红康 JVM 笔记 Day06|虚拟机栈
  • [激光原理与应用-318]:结构设计 - Solidworks - 草图
  • 损耗源:导线电阻与趋肤效应
  • 深度学习②【优化算法(重点!)、数据获取与模型训练全解析】
  • 线上日志排查问题
  • MCP 与 Function Calling 打开真实世界的两种“母体”方式
  • Spring 框架深度解析:从核心原理到实战应用
  • GitLab CI :深入剖析 gl-sbom-report.cdx.json 解码“数字身份证”
  • linux下的网络编程
  • 快速入门Vue3——初体验
  • 6020角度双环控制一种用于电机控制的策略
  • 智能合约漏洞检测技术综述:守护区块链世界的“自动售货机”
  • 在通义灵码中配置MCP服务
  • uniapp使用map打包app后自定义气泡不显示解决方法customCallout
  • JavaWeb前端05(Vue工程化,Vue组件两种风格:组合式API 和 选项式API)及简单案例)
  • 豆包 + 蘑兔,破解写歌难题!
  • 知识蒸馏 Knowledge Distillation 论文 Generalized Knowledge Distillation (GKD) 目标函数的演化
  • 【Cmake】Cmake概览
  • 使用GMail API 发送邮箱
  • OpenSCA开源社区每日安全漏洞及投毒情报资讯|21th Aug. , 2025
  • 前端github-workflows部署腾讯云轻量服务器
  • 实用R语言机器学习指南:从数据预处理到模型实战(附配套学习资源)
  • docker 查看容器 docker 筛选容器
  • 循环神经网络实战:GRU 对比 LSTM 的中文情感分析(三)
  • Flask数据库迁移实战指南