异步开发和事件总线开发的区别

文章目录
  1. 1. 什么时候需要消息总线?
    1. 1.1. 适用场景:
    2. 1.2. 异步方式提交任务
    3. 1.3. 消息总线的优缺点

什么时候需要消息总线?

消费总线似乎一直和消息队列在一起在分布式环境一起来实现
本地也可以使用 reactor 模式来实现消息总线

适用场景:

多个订阅者:需要同时通知多个不同的组件,且组件之间没有依赖,订阅方可以动态添加/移除
动态订阅:运行时需要添加/移除订阅者
背压控制:需要处理生产者消费者速度不匹配
复杂事件流:需要事件过滤、转换、组合等操作

一个事件 需要出发多种反应包括 日志,缓存等
消息总线可以将一个事件分发到多个目标
目标可以是多个组件

异步方式提交任务

通常情况下异步和回调的机制也可以实现上面消息总线的一部分功能,而且还简单

消息总线的优缺点

高耦合 (High Coupling):TaskService 强依赖于 CacheService 和 LogService。它必须“知道”有哪些服务需要被通知。

违反开闭原则 (Violates Open/Closed Principle):如果未来新增一个 NotificationService,当任务更新时需要发送邮件通知,你必须修改 TaskService 的代码,在 updateTask 方法里增加一个新的调用。这使得 TaskService 变得不稳定,难以维护。

职责不清:TaskService 的核心职责是处理任务业务,但现在它还承担了“协调和通知其他模块”的职责,这会让它的逻辑越来越臃肿。

这种

低耦合 (Low Coupling):TaskService (发布者) 和 CacheService/LogService (订阅者) 之间没有直接依赖。它们都只依赖于中间人 TaskEventBroker。

高扩展性 (High Extensibility):当你需要新增一个 NotificationService 时,完全不需要修改 TaskService。你只需要创建 NotificationService 并让它自己去订阅事件即可。这完全符合开闭原则(对扩展开放,对修改关闭)。

职责单一 (Single Responsibility):每个模块只关心自己的事。TaskService 只管发事件,CacheService 只管响应事件并刷新缓存。

// 发布者
@Service
public class TaskService {
@Autowired
private TaskEventBroker eventBroker;

public void updateTask(Task task) {
    // 1. 更新数据库中的任务...
    db.save(task);

    // 2. 只负责发布一个“任务已变更”的事件,不关心谁会收到
    eventBroker.publish(); 
    log.info("任务变更事件已发布");
}

}

// 订阅者1
@Service
public class CacheService {
@Autowired
public CacheService(TaskEventBroker eventBroker) {
// 在构造时就订阅事件
eventBroker.subscribe(signal -> this.refresh());
}

public void refresh() { /* ...刷新缓存的逻辑... */ }

}

// 订阅者2
@Service
public class LogService {
public LogService(TaskEventBroker eventBroker) {
eventBroker.subscribe(signal -> this.recordUpdate());
}

public void recordUpdate() { /* ...记录日志的逻辑... */ }

}

// 新增的订阅者3 (无需修改任何已有代码)
@Service
public class NotificationService {
public NotificationService(TaskEventBroker eventBroker) {
eventBroker.subscribe(signal -> this.sendEmail());
}

public void sendEmail() { /* ...发送邮件的逻辑... */ }

}