观察者模式与发布-订阅可分层融合:Subject只向EventBus发事件,Observer向EventBus订阅;事件轻量语义化、动词过去时命名、字段精简;订阅端异步处理并支持重试与监控。

观察者模式本身是同步、进程内、紧耦合的,但它的核心思想——“状态变更触发通知”——完全可以与发布-订阅(Pub/Sub)的解耦和异步特性融合,形成一种更实用的事件驱动架构。关键不是强行把两者等同,而是分层设计:用观察者模式组织模块内响应逻辑,用发布-订阅机制承载跨组件、跨线程甚至跨服务的事件流转。
明确角色分工:谁负责通知,谁负责分发
不要让 Subject 直接持有 Observer 实例并逐个调用 update()。而是让 Subject 在状态变化时,只做一件事:向一个统一的事件总线(Event Bus)发布一个事件对象。
- Subject(被观察者)只依赖 EventBus 接口,不感知任何具体监听器
- Observer(观察者)不再主动注册到 Subject,而是向 EventBus 订阅特定事件类型(如 UserUpdatedEvent、OrderPaidEvent)
- EventBus 扮演消息代理角色,内部可基于内存队列(如 Disruptor)、线程池或集成 Kafka/RabbitMQ 实现异步投递
事件建模要轻量且语义清晰
事件不是数据搬运工,而是业务意图的表达。避免传递原始 Entity 或上下文对象,而是封装最小必要信息。
- 命名体现动词+过去时:UserRegisteredEvent、InventoryDeductedEvent
- 字段只含关键业务标识:userId、orderId、timestamp、version(用于幂等)
- 不放 service、repository 等运行时依赖,确保事件可序列化、可审计、可重放
订阅端按需异步处理,避免阻塞主线程
监听器(Subscriber)收到事件后,不应在事件分发线程中执行耗时操作(如发邮件、调远程接口、写数据库)。应立即转入业务线程池或消息队列。
- 使用 @EventListener + @Async(Spring)或自定义 ExecutorService 提交任务
- 对强一致性要求高的场景(如库存扣减),先本地落库标记“事件已接收”,再异步补偿
- 允许监听器声明消费失败后的重试策略(次数、间隔、死信路由)
保留观察者模式的可控性优势
纯 Pub/Sub 容易失控:谁发了什么?谁订了什么?有没有漏处理?可在 EventBus 层叠加轻量治理能力,继承观察者模式的可追踪性。
- 提供 registerListener(Class<T> eventType, Consumer<T> handler) 方法,支持运行时动态增删监听器
- 记录每个事件类型的活跃订阅数、平均处理耗时、失败率(用于告警)
- 测试阶段可替换为同步内存总线,便于单测和调试;生产环境自动切换为异步实现


















