示例工程教程【免费下载链接】java-design-patternsDesign patterns implemented in Java项目地址https://gitcode.com/GitHub_Trending/ja/java-design-patterns点击查看免费下载导读本文以 java-design-patterns 仓库中data-bus模块data-bus/README.md为核心系统讲解 Data Bus数据总线又称 Event Bus / Message Bus设计模式。该模式为系统各组件提供一个集中式通信通道组件之间无需直接互相引用即可交换数据从而获得低耦合、易扩展、易维护的架构收益。读完本文你将掌握 Data Bus 模式的核心思想、Java 实现结构、消息按类型选择性分发的机制以及它在事件驱动、微服务等场景下的适用边界与取舍。Data Bus 模式是什么Data Bus 设计模式的目标是提供一个集中式通信通道让系统中各种组件无需直接连接即可交换数据从而促进松耦合并提升系统的可扩展性与可维护性。别名Event Bus事件总线、Message Bus消息总线。一句话概括Data Bus 是一种根据被传递的消息或事件类型来连接应用组件的设计模式——组件只按类型接收自己关心的消息互相之间不产生直接依赖。现实类比机场广播系统大型机场中有航空公司、乘客、行李搬运工、安检人员等多类实体它们都需要互通信息。若让每个实体直接与其他实体通信关系网会极其复杂。机场实际采用的做法是使用一套**集中式广播系统即 Data Bus**统一发布航班信息、安检警报等关键更新各实体只监听与自己相关的消息。这样既解耦了通信过程又能无破坏地接入新实体与 Data Bus 在 Java 中的定位一致。消息分发流程程序化示例在线活动报名应用假设你有一个支持在线预订和参与活动的应用希望把活动广告这类通知发送给社区普通成员但不发给活动管理员/组织者而管理员则需要收到新广告已发送给全体成员这类时机通知。Data Bus 让两类成员各自只接受特定类型的消息双方互不知晓对方类别的存在只知道正在传递的消息类型。仓库中该模块源码位于>public interface Member extends ConsumerDataType { void accept(DataType event); }2. 定义事件数据类型 DataType 与 AbstractDataType通过总线发布的数据必须实现 DataType 接口它承载事件在哪条总线上发送的回指引用public interface DataType { DataBus getDataBus(); void setDataBus(DataBus dataBus); }AbstractDataType 使用 Lombok 的Getter/Setter提供默认实现具体事件类型只需继承它并携带自己的业务字段即可Getter Setter public class AbstractDataType implements DataType { private DataBus dataBus; }仓库内置了三种事件类型位于>public class DataBus { private static final DataBus INSTANCE new DataBus(); private final SetMember listeners new HashSet(); public static DataBus getInstance() { return INSTANCE; } public void subscribe(final Member member) { this.listeners.add(member); } public void unsubscribe(final Member member) { this.listeners.remove(member); } public void publish(final DataType event) { event.setDataBus(this); listeners.forEach( listener - listener.accept(event)); } }要点说明单例DataBus.getInstance()返回全局唯一实例源码注释明确标注该实现使用 Singleton。publish的第一步是event.setDataBus(this)把事件回指到当前总线——这正是StatusMember能在收到事件后反向通过总线再发消息的前提见下文。同步语义从App.java的类注释可知这是一个同步数据总线——publish方法在所有成员都接收并处理完事件之后才返回。多对多任意数量的发布者可以向总线发数据任意数量的成员接收数据所有成员收到的是同一份数据各成员收到数据的先后顺序是实现的细节HashSet不保证顺序。4. 按类型选择性接收的成员实现普通成员MessageCollectorMember 只处理MessageData类型的消息其他类型直接忽略public class MessageCollectorMember implements Member { private final String name; private final ListString messages new ArrayList(); public MessageCollectorMember(String name) { this.name name; } Override public void accept(final DataType data) { if (data instanceof MessageData) { handleEvent((MessageData) data); } } }handleEvent内部通过LOGGER.info({} sees message {}, name, data.getMessage())打印日志并把消息存入messages列表getMessages()返回不可变副本List.copyOf(messages)防止外部修改内部状态。管理员/组织者StatusMember 则处理StartingData与StoppingData两类事件public class StatusMember implements Member { private final int id; private LocalDateTime started; private LocalDateTime stopped; public StatusMember(int id) { this.id id; } Override public void accept(final DataType data) { if (data instanceof StartingData) { handleEvent((StartingData) data); } else if (data instanceof StoppingData) { handleEvent((StoppingData) data); } } }值得注意的源码细节当StatusMember收到StoppingData应用停止时它会借助事件上回指的getDataBus()反向发布一条告别消息private void handleEvent(StoppingData data) { stopped data.getWhen(); LOGGER.info(Receiver {} sees application stopping at {}, id, stopped); LOGGER.info(Receiver {} sending goodbye message, id); data.getDataBus().publish(MessageData.of(String.format(Goodbye cruel world from #%d!, id))); }这说明 Data Bus 中的成员既是消费者也可以作为发布者成员之间通过总线形成环形消息流而彼此仍不知道对方的存在。5. 组合演示 AppApp.java 串联了完整流程订阅 → 发布启动事件 → 发布消息 → 中途订阅新成员 → 退订旧成员 → 发布停止事件class App { public static void main(String[] args) { final var bus DataBus.getInstance(); bus.subscribe(new StatusMember(1)); bus.subscribe(new StatusMember(2)); final var foo new MessageCollectorMember(Foo); final var bar new MessageCollectorMember(Bar); bus.subscribe(foo); bus.publish(StartingData.of(LocalDateTime.now())); } }当总线发布StartingData时输出如下02:33:57.627 [main] INFO com.iluwatar.databus.members.StatusMember - Receiver 2 sees application started at 2022-10-26T02:33:57.613529100 02:33:57.633 [main] INFO com.iluwatar.databus.members.StatusMember - Receiver 1 sees application started at 2022-10-26T02:33:57.613529100如上所示MessageCollectorMember只接受MessageData因此看不到StartingData/StoppingData这两类只有StatusMember管理员/组织者可见的事件。这种按消息类型的选择性分发恰好阻止了普通成员收到管理类通知。如果沿 App 的完整执行序列继续运行发布MessageData.of(Only Foo should see this)、订阅 bar、发布MessageData.of(Foo and Bar should see this)、退订 foo、发布MessageData.of(Only Bar should see this)、发布StoppingData可以看到普通成员按订阅/退订状态动态接收消息而StatusMember收到停止事件后又向总线回发告别消息。6. 测试印证DataBusTest.java 用 Mockito 直接验证了总线契约publishedEventIsReceivedBySubscribedMember订阅后发布事件then(member).should().accept(event)断言订阅者收到事件publishedEventIsNotReceivedByMemberAfterUnsubscribing退订后发布事件断言成员不再收到。MessageCollectorMemberTest 与 StatusMemberTest 则分别验证了各成员只处理自己关心的消息类型测试与源码共同构成了类型选择性分发行为的证据链。何时使用 Data Bus 模式符合以下情况时Data Bus 是合适的选择多个组件需要共享数据或事件但不希望直接耦合复杂的事件驱动系统其中信息流动随运行动态变化分布式系统组件可能部署在不同环境中微服务架构下的服务间通信。Data Bus 模式的真实应用场景大规模应用中的事件处理系统微服务架构中的服务间通信实时数据处理系统如股票交易平台类似 Spring 的框架生态特别是其application event应用事件机制。优点与权衡优点Benefits松耦合组件交互不产生直接依赖灵活新增订阅者或发布者无需影响既有组件可扩展各组件可独立扩展可复用总线和组件可在不同系统中复用。代价Trade-offs复杂度引入总线会给系统架构增加一层复杂度性能开销额外的通信层可能引入延迟调试困难在事件繁多的系统中追踪数据流会比较困难。与其他设计模式的关系Mediator中介者同样促进组件间通信但 Mediator 把控制逻辑集中起来Data Bus 则把控制分散到总线与各成员之间。Observer观察者Data Bus 在本质上是发布-订阅机制与 Observer 通知多个对象状态变化的方式相似。从 App.java 的注释也可以看到Data Bus 与观察者模式相似——成员在总线上注册后接收发布的每份数据并可自行决定是否响应某条消息。Publish/Subscribe发布-订阅Data Bus 常以发布-订阅机制实现——发布者向总线投递消息而无需了解订阅者是谁。参考资料本文内容以>赞分享示例工程教程【免费下载链接】java-design-patternsDesign patterns implemented in Java项目地址https://gitcode.com/GitHub_Trending/ja/java-design-patterns点击查看免费下载相关推荐macOS新手向5分钟装好notepad--跨平台文本编辑器中文编码与双窗口对比全带上macOS新手向5分钟装好notepad 跨平台文本编辑器中文编码与双窗口对比全带上 你习惯用系统自带TextEdit记笔记一碰到 .c 文件或GBK编码示例工程教程Truffle Dashboard 消息总线通用类型包 truffle/dashboard-message-bus-common 详解Truffle Dashboard 消息总线通用类型包 truffle/dashboard message bus common 详解 导读 truffle区块链开发工具Web3Java 设计模式Acyclic Visitor无环访问者模式解析与源码实战 —— 基于 java-design-patterns 仓库 acyclic-visitor 模块Java 设计模式Acyclic Visitor无环访问者模式解析与源码实战 —— 基于 java design patterns 仓库 acyclic示例工程教程上一篇Flutter Assets Audio Player与后台服务集成实现后台播放和锁屏控制下一篇BTCPay Server视频行业订阅支付方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?