【bird-java】分布式服务间的事件总线EventBus
什么是EventBus
EventBus是对发布-订阅模式的一种实现。其以一种非常优雅的方式实现了组件间的解耦与通信,在Android开发、DDD等领域都有非常广泛的应用。
事件流大致如下:
- Producer向EventBus发送事件。
- EventBus向所有监听了该事件的Consumer推送事件。
- 监听了该事件的Consumer消费事件。
注:一个组件即可以是Producer,也可以是Consumer。
分布式服务间的EventBus
在分布式系统中,事件在服务之间的传递要比单机EventBus复杂很多。有没有一种适用于分布式服务之间的,并且事件传递就像单机一样简单的EventBus呢?在GitHub上搜索了JAVA实现的EventBus,排名前十的几乎都是用于Android或JAVA的单机事件总线。良久之后...还是自己动手吧。集群环境下的EventBus比单机版需要多考虑一些问题,比如:
- 服务集群部署的情况下,如何保证每个集群均可订阅该事件,且每个集群只能消费一次该事件。
- 如何实现一个服务内部多个`xxxService`订阅同一事件。
解决方案:
- 使用`kafka`实现集群间的发布订阅(基于`topic`),同一集群处于同一个kafka的consumer-group来保证每个集群只会消费一次该事件。
- 服务在启动时可反射获得所有实现了`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的更多相关文章
- vue中央事件总线eventBus的简单理解和使用
公共事件总线eventBus的实质就是创建一个vue实例,通过一个空的vue实例作为桥梁实现vue组件间的通信.它是实现非父子组件通信的一种解决方案. 用法如下: 第一步:项目中创建一个js文件(我通 ...
- ASP.NET Core基于微软微服务eShopOnContainer事件总线EventBus的实现
这个EventBus的实现是基于微软微服务https://github.com/dotnet-architecture/eShopOnContainers项目的,我把它从项目中抽离出来,打包成nuge ...
- java分布式服务框架Dubbo的介绍与使用
1. Dubbo是什么? Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案.简单的说,dubbo就是个服务框架,如果没有分布式的需求,其实是不需 ...
- 转载:java分布式服务框架Dubbo的介绍与使用
1. Dubbo是什么? Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案.简单的说,dubbo就是个服务框架,如果没有分布式的需求,其实是不需 ...
- Java分布式服务框架Dubbo初探(待实践)
Dubbo是什么? Dubbo[]是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案. 其核心部分包含: 远程通讯: 提供对多种基于长连接的NIO框架抽象封 ...
- 基于ASP.NET Core 5.0使用RabbitMQ消息队列实现事件总线(EventBus)
文章阅读请前先参考看一下 https://www.cnblogs.com/hudean/p/13858285.html 安装RabbitMQ消息队列软件与了解C#中如何使用RabbitMQ 和 htt ...
- 事件总线 EventBus
661. .net中事件模型很优雅的实现了观察者模式,同时被大量的使用在各种框架中. [2016-04-30 10:52:42]662. Prism框架中实现了一个典型的EventAggregator ...
- Guava: 事件总线EventBus
EventBus 直译过来就是事件总线,它使用发布订阅模式支持组件之间的通信,不需要显式地注册回调,比观察者模式更灵活,可用于替换Java中传统的事件监听模式,EventBus的作用就是解耦,它不是通 ...
- 自己动手写事件总线(EventBus)
本文由云+社区发表 事件总线核心逻辑的实现. EventBus的作用 Android中存在各种通信场景,如Activity之间的跳转,Activity与Fragment以及其他组件之间的交互,以及在某 ...
随机推荐
- Pyqt4的对话框 -- 文件对话框
文件对话框允许用户选择文件或文件夹,被选择的文件可进行读或写操作 # QInputDialog 文件对话框 # 本示例包含一个菜单栏,一个状态栏和一个被设置为中心部件的文本编辑器. # 状态栏的状态信 ...
- python之Character string
1.python字符串 字符串是 Python 中最常用的数据类型.我们可以使用引号('或")来创建字符串,l Python不支持单字符类型,单字符也在Python也是作为一个字符串使用. ...
- while求1+2+3+4+5+6....100的和
#求1到100的和. #声明i初始变量 i = 1 #声明y初始变量 y = 1 #开始循环条件为i不等于100,则执行while代码块 while i != 100: #给i加1 i += 1 #y ...
- 【vue系列之三】从一个vue-pdf-shower,说说vue组件和npm包
前言 从去年年初开始,自己便下决心要写一个vue系列的博客,但时至今日,才写系列的第三篇博客,想来甚是惭愧. 但是慢归慢,每一篇都要保证质量,以及要写出自己的心路历程,防止自己工作中填的坑再让读者走一 ...
- ArrayList排序算法的源码
ArrayList,排序方法的调用过程 // 排序方法 public void sort(Comparator<? super E> c) { final int expectedModC ...
- sqlalchemy-数据库操作
import datetime from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarat ...
- 树莓派搭建WEB服务器
树莓派搭建WEB的教程网上有许多,但感觉每一篇都有一些问题,这次我将网上的教程汇总,并亲身实践,将注意的问题都写进去,方便新手学习! 目录:1,安装nginx+sqlite+php5打造轻量级服务器, ...
- bzoj 3295: [Cqoi2011]动态逆序对(树套树 or CDQ分治)
Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计 ...
- C/C++中substr函数的应用(简单讲解)
substr(字符串,截取开始位置,截取长度) //返回截取的字 substr('Hello World',0,1) //返回结果为 'H' *从字符串第一个字符开始截取长度为1的字符串 subst ...
- BZOJ 1207: [HNOI2004]打鼹鼠【妥妥的n^2爆搜,dp】
1207: [HNOI2004]打鼹鼠 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3259 Solved: 1564[Submit][Statu ...