什么是EventBus
EventBus是对发布-订阅模式的一种实现。其以一种非常优雅的方式实现了组件间的解耦与通信,在Android开发、DDD等领域都有非常广泛的应用。

事件流大致如下:

  • Producer向EventBus发送事件。
  • EventBus向所有监听了该事件的Consumer推送事件。
  • 监听了该事件的Consumer消费事件。

注:一个组件即可以是Producer,也可以是Consumer。

分布式服务间的EventBus
在分布式系统中,事件在服务之间的传递要比单机EventBus复杂很多。有没有一种适用于分布式服务之间的,并且事件传递就像单机一样简单的EventBus呢?在GitHub上搜索了JAVA实现的EventBus,排名前十的几乎都是用于Android或JAVA的单机事件总线。良久之后...还是自己动手吧。集群环境下的EventBus比单机版需要多考虑一些问题,比如:

  1. 服务集群部署的情况下,如何保证每个集群均可订阅该事件,且每个集群只能消费一次该事件。
  2. 如何实现一个服务内部多个`xxxService`订阅同一事件。

解决方案:

  1. 使用`kafka`实现集群间的发布订阅(基于`topic`),同一集群处于同一个kafka的consumer-group来保证每个集群只会消费一次该事件。
  2. 服务在启动时可反射获得所有实现了`IEventHandler<TEventArg>`的类并缓存,服务消费消息时获取所有注册了该消息的handler并调用其`HandleEvent`方法。

部分关键源码

1、事件消息的定义

public abstract class EventArg implements IEventArg{

    private Date eventTime;

    public EventArg(){
eventTime = new Date();
} public Date getEventTime() {
return eventTime;
} public void setEventTime(Date eventTime) {
this.eventTime = eventTime;
}
}

事件消息默认记录创建时间,可扩展其他字段,比如发送时间、标识等。

2、使用spring-kafka发送消息

/**
* kafka事件注册器,向kafka队列中push消息
*/
@Component
public class KafkaRegister implements IEventRegister { @Autowired(required = false)
private KafkaTemplate<String,IEventArg> kafkaTemplate; /**
* 事件注册
*
* @param eventArg 事件参数
*/
@Override
public void regist(IEventArg eventArg) {
kafkaTemplate.send(getTopic(eventArg),eventArg);
} /**
* 获取kafka的topic
*
*
* @param eventArg
* @return topic
*/
private String getTopic(IEventArg eventArg){
return eventArg.getClass().getName();
}
}

3、消费kafka消息并执行当前服务中所有订阅了该消息的事件

/**
* kafka事件监听器
*/
public class KafkaEventArgListener implements MessageListener<String,EventArg> { @Autowired
private IEventHandlerFactory eventHandlerFactory; @Override
public void onMessage(ConsumerRecord<String, EventArg> consumerRecord) {
if (consumerRecord == null) return;
EventArg value = consumerRecord.value(); Set<IEventHandler> handlers = eventHandlerFactory.getHandlers(value);
if (handlers == null) return;
for (IEventHandler handler : handlers) {
handler.HandleEvent(value);
}
}
}

EventBus的使用

1、事件的定义。所有事件均继承于上文EventArg抽象类,示例如下:

public class TestEventArg extends EventArg{
private String value; public String getValue() {
return value;
} public void setValue(String value) {
this.value = value;
}
}

2、事件发布。示例代码:

eventBus.push(new TestEventArg());

3、事件订阅。一个服务发布事件之后,任何服务中的任何`xxxServiceImpl`类均可订阅该事件,实现`IEventHandler<TEventArg>`接口即可完成事件的订阅,示例如下:

public class FormServiceImpl extends AbstractServiceImpl<Form> implements FormService,IEventHandler<TestEventArg> {

    @Override
public void HandleEvent(TestEventArg eventArg) {
System.out.println("notify zero======");
}
}

整体来说,使用还是很简单的,EventBus实现与使用示例收录于bird-java项目中,项目地址:https://github.com/liuxx001/bird-java

【bird-java】分布式服务间的事件总线EventBus的更多相关文章

  1. vue中央事件总线eventBus的简单理解和使用

    公共事件总线eventBus的实质就是创建一个vue实例,通过一个空的vue实例作为桥梁实现vue组件间的通信.它是实现非父子组件通信的一种解决方案. 用法如下: 第一步:项目中创建一个js文件(我通 ...

  2. ASP.NET Core基于微软微服务eShopOnContainer事件总线EventBus的实现

    这个EventBus的实现是基于微软微服务https://github.com/dotnet-architecture/eShopOnContainers项目的,我把它从项目中抽离出来,打包成nuge ...

  3. java分布式服务框架Dubbo的介绍与使用

    1. Dubbo是什么? Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案.简单的说,dubbo就是个服务框架,如果没有分布式的需求,其实是不需 ...

  4. 转载:java分布式服务框架Dubbo的介绍与使用

    1. Dubbo是什么? Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案.简单的说,dubbo就是个服务框架,如果没有分布式的需求,其实是不需 ...

  5. Java分布式服务框架Dubbo初探(待实践)

    Dubbo是什么? Dubbo[]是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案. 其核心部分包含: 远程通讯: 提供对多种基于长连接的NIO框架抽象封 ...

  6. 基于ASP.NET Core 5.0使用RabbitMQ消息队列实现事件总线(EventBus)

    文章阅读请前先参考看一下 https://www.cnblogs.com/hudean/p/13858285.html 安装RabbitMQ消息队列软件与了解C#中如何使用RabbitMQ 和 htt ...

  7. 事件总线 EventBus

    661. .net中事件模型很优雅的实现了观察者模式,同时被大量的使用在各种框架中. [2016-04-30 10:52:42]662. Prism框架中实现了一个典型的EventAggregator ...

  8. Guava: 事件总线EventBus

    EventBus 直译过来就是事件总线,它使用发布订阅模式支持组件之间的通信,不需要显式地注册回调,比观察者模式更灵活,可用于替换Java中传统的事件监听模式,EventBus的作用就是解耦,它不是通 ...

  9. 自己动手写事件总线(EventBus)

    本文由云+社区发表 事件总线核心逻辑的实现. EventBus的作用 Android中存在各种通信场景,如Activity之间的跳转,Activity与Fragment以及其他组件之间的交互,以及在某 ...

随机推荐

  1. Markdown 常用语法

    1.标题 # 一级标题 ## 二级标题 ### 三级标题 2.字体 *斜体* **粗体** ~~删除线~~<u>下划线</u> 3.引用 > 引用文字 4.无序列表 - ...

  2. Appium 命令行模式下遇到的问题总结及解决方案 npm ERR! tar.unpack unzip(或者untar) error

    安装了GUI Appium后,卸载删除问题后,使用命令行模式安装. 一. 遇到问题: nalideMacBook-Pro:~ nali$ npm install -g appium npm ERR! ...

  3. Java中的移动和复制

    public static boolean Move(File srcFile, String destPath) { // Destination directory File dir = new ...

  4. socket模型处理多个客户端

    最近学完了简单的socket编程,发现其实socket的网络编程其实并没有什么难度,只是简单的函数调用,记住客户端与服务端的步骤,写起来基本没有什么问题. 在服务器程序的设计中,一个服务器不可能只相应 ...

  5. DAY5-小别-2018-1-15

    有两天没有写了,前天考完试出去浪了,惭愧自己没有学习:昨天,启程回家看完了循环内容的视频,晚上十点半火车到站,没抽出时间写了,还看了<黑客帝国>,有点小感触,人工智能的时代即将到来,我们该 ...

  6. dm-verity

    一.Device Mapper: dm-verity是内核子系统的Device Mapper中的一个子模块,所以在介绍dm-verity之前先要介绍一下Device  Mapper的基础知识. Dev ...

  7. I2C通讯协议

    1.基本概念 主机            初始化发送,产生时钟信号和终止发送的器件 从机             被主机寻址的器件  发送器          发送数据到总线的器件 接收器       ...

  8. 个人项目--“”小鱼企业级开发系统“”Svn地址分享

    由于精力有限,博主现在只维护这一个系统,会不时的更新代码提交. ""小鱼企业级开发系统""的Svn地址:http://code.taobao.org/svn/S ...

  9. element-ui,router.push到其他路由,菜单栏不会高亮对应的路由

    使用饿了吗的路由,使用this.$router.push({path: ''})跳到其他的路由,菜单不会高亮. 如图所示,点击图上三个位置,需要使用this.$router.push({path: ' ...

  10. Luogu P1231 教辅的组成

    Luogu P1231 教辅的组成 题目背景 滚粗了的HansBug在收拾旧语文书,然而他发现了什么奇妙的东西. 题目描述 蒟蒻HansBug在一本语文书里面发现了一本答案,然而他却明明记得这书应该还 ...