发布于2026-07-09 阅读(0)
扫一扫,手机访问
不妨先从这个问题说起:在 Ja va 系统中,当订单创建后需要同时通知库存服务和通知服务,你会怎么做?最直接的写法可能是让订单服务直接调用两者——但这样一来,新增一个积分服务或日志服务,订单服务的代码就需要跟着改。久而久之,耦合越缠越紧。
事件总线(Event Bus)正是为解耦这类场景而生的轻量级异步通信机制。它让发布者与订阅者不再直接引用彼此,而是通过一个消息总线完成交互。一句话概括核心:发布者只管发,订阅者只管接,总线负责分——这天然契合面向对象设计里“高内聚、低耦合”的原则。

Ja va 生态里成熟的事件总线方案不少,选哪个,往往取决于项目规模和现有的依赖约束。
@Subscribe 注解即可完成订阅。但它本身不支持异步,需要手动包装到线程池;事件类型依赖运行时 Class 匹配,类型安全性相对弱一些。@Async)、事务绑定和条件监听。事件必须继承 ApplicationEvent 或使用泛型事件(Spring 4.2+),类型安全做得很到位。事件本身应当是纯粹的数据载体。遵循面向对象的封装原则:字段私有,只提供 getter,不提供 setter,防止监听器意外篡改状态。推荐使用 Ja va 14+ 的 record,或者通过构造器初始化的普通类:
public record OrderCreatedEvent(String orderId, BigDecimal amount, String userId) {}// 或传统写法:public class PaymentProcessedEvent { private final String transactionId; private final LocalDateTime timestamp; public PaymentProcessedEvent(String transactionId) { this.transactionId = transactionId; this.timestamp = LocalDateTime.now(); } // 只有 getter,无 setter}一个需要避免的坑:千万别用 Map 或 JSONObject 传递事件。那样会丢掉编译期类型检查,彻底违背面向对象的设计初衷。
以 Spring Event 为例,可以很直观地看到什么是“面向对象协作”。每个监听器是一个独立的 Bean,职责单一,生命周期由容器托管:
@Componentpublic class InventoryService { @EventListener @Async // 启用异步执行(需启用 @EnableAsync) public void onOrderCreated(OrderCreatedEvent event) { // 扣减库存逻辑,不阻塞订单主流程 inventoryClient.reserve(event.orderId(), event.amount()); }}@Componentpublic class NotificationService { @EventListener public void onPaymentProcessed(PaymentProcessedEvent event) { // 同步发信息(也可加 @Async 实现异步) smsClient.send("Payment confirmed: " + event.transactionId()); }}这里有几个关键点值得留意:
@Async 让监听器在独立线程中执行,发布者无需关心线程模型;面向对象强调对象状态与行为的一致性,事件总线也不例外。实践中,有几个问题频繁出现:
@EventListener 注解不会被扫描,事件永远送不到。@Async 方法运行在新线程中,默认脱离原事务上下文。如果需要事务,得单独加上 @Transactional。OrderShippedEvent),而不是“请执行某操作”——那是 Command 模式的职责。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8