使用Guava EventBus构建publish/subscribe系统
Google的Guava类库提供了EventBus,用于提供一套组件内publish/subscribe的解决方案.事件总线EventBus,用于管理事件的注册和分发。在系统中,Subscribers会向EventBus注册自己感兴趣的事件,而publishers会将自己产生的事件发布给EventBus。在系统中,EventBus事件分发默认设置为串行的(可设置),我们在Subscribers中的事件处理速度要快,不要阻塞当前的事件纷发进程。

创建EventBus实例
EventBus提供两个构造函数,可用于创建Evnet实例,如下所示。
@Test
public void should_create_event_bus_instance() throws Exception {
EventBus eventBus = new EventBus();
//string构造参数,用于标识EventBus
EventBus eventBus1 = new EventBus("My Event Bus");
}
Subscribe事件
- Subsciber对象需要定义handler method,用于接受并处理一个通知事件对象
- 使用Subscribe标签标识事件handler method
- Subscriber向EvenetBus注册,通过EventBus.register方法进行注册
Post事件
post一个事件很简单,只需要调用EventBus.post方法即可以实现。EventBus会调用Subscriber的handler method处理事件对象。
定义handler Method
方法接受一个事件类型对象,当publisher发布一个事件,eventbus会串行的处理event-handling method, 所以我们需要让event-handing method处理的速度快一些,通常我们可以通过多线程手段来解决延迟的问题。
Concurrency
EventBus可以通过使用AllowConcurrentEvent注解来实现并发调用handle method。当handler method被标记为AllowConcurrentEvent(replace Subscribe标签),我们认为handler Method是线程安全的。
Code Sample
例子中,我们使用cookie店为例,为了简单起见,系统中只定义了五个对象:
- EmptyEvent对象:用于表明CookieContaier cookie数量为0
- CookieContaier对象:用于Cookie的存储,当cookie数量为0时,会发布EmptyEvent事件
- CookieSeller: EmptyEvent事件订阅者
- CookieMailBoss:EmptyEvent事件订阅者
- HandlerService: 定义handler-method接口,使用@Subscribe标注
public interface HandlerService {
@Subscribe
void handler(EmptyEvent emptyEvent);
}
public class CookieSeller implements HandlerService {
public CookieSeller(EventBus eventBus) {
eventBus.register(this);
}
public void handler(EmptyEvent emptyEvent) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.getClass().getName() + ":" + "receiving empty event");
}
}
public class CookieMallBoss implements HandlerService {
public CookieMallBoss(EventBus eventBus) {
eventBus.register(this);
}
public void handler(EmptyEvent emptyEvent) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.getClass().getName() + ":" + "receiving empty event");
}
}
getCookie函数,会计算事件触发publish时间
public class CookieContainer {
private EventBus eventBus;
private AtomicInteger numberOfCookie = new AtomicInteger();
public CookieContainer(EventBus eventBus) {
this.eventBus = eventBus;
}
public void setNumberOfCookie(int intenger) {
numberOfCookie.set(intenger);
}
public void getACookie() {
if (numberOfCookie.get() == 0) {
long start = System.currentTimeMillis();
eventBus.post(new EmptyEvent());
System.out.println("Publishing event time: " + (System.currentTimeMillis() - start) + " ms");
return;
}
numberOfCookie.decrementAndGet();
System.out.println("retrieve a cookie");
}
}
public class EmptyEvent {
}
Code Test Case
设置cookie数量为三,当第四次取cookie会触发empty事件,EventBus会串行的发布事件。
@Test
public void should_recv_event_message() throws Exception {
EventBus eventBus = new EventBus();
CookieContainer cookieContainer=new CookieContainer(eventBus);
HandlerService cookieSeller = new CookieSeller(eventBus);
HandlerService cookieMallBoss = new CookieMallBoss(eventBus);
//设置cookie的数量为3
cookieContainer.setNumberOfCookie(3);
//用户取三次之后cookie数量为空
cookieContainer.getACookie();
cookieContainer.getACookie();
cookieContainer.getACookie();
System.out.println("=======再次取cookie, 触发Empty事件发布============");
cookieContainer.getACookie();
}
测试结果如下所示,当第四次getCookie时,触发EmptyEvent事件发布。耗时为4013ms
retrieve a cookie
retrieve a cookie
retrieve a cookie
=======触发事件发布============
com.mj.ele.guava.CookieMallBoss:receiving empty event
com.mj.ele.guava.CookieSeller:receiving empty event
Publishing event time: 4013 ms
使用AllowConcurrentEvents标签取Subscribe,设置cookie数量为三,当第四次取cookie会触发empty事件,EventBus会并行的发布事件。
修改Handler method接口,标记为@AllowConcurrentEvents
public interface HandlerService {
@AllowConcurrentEvents
void handler(EmptyEvent emptyEvent);
}
测试代码和串行代码一致,测试结果如下所示,事件发布耗时只需1ms
retrieve a cookie
retrieve a cookie
retrieve a cookie
=======触发事件发布============
Publishing event time: 1 ms
Conclusion
本文讲解了如何使用Guava的EventBus来构建publish/subscribe系统,分别给出了串行和并行发布的使用方法,希望能够给读者带来一些帮助和启发。
使用Guava EventBus构建publish/subscribe系统的更多相关文章
- 设计模式:Observer(观察者)—— Guava EventBus
本文分为三个部分: Observer(观察者) Guava EventBus详解 Guava EventBus使用示例 1. Observer(观察者) 1.1 背景 我们设计系统时, ...
- 【RabbitMQ】Publish/Subscribe
Publish/Subscribe 在上一节我们创建了一个work queue.背后的设想为每个任务被分发给明确的消费者.这节内容我们将做一些完全不同的事情 -- 我们将发送一条消息给多个消费者.这种 ...
- RabbitMQ学习总结 第四篇:发布/订阅 Publish/Subscribe
目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...
- (转)RabbitMQ消息队列(四):分发到多Consumer(Publish/Subscribe)
上篇文章中,我们把每个Message都是deliver到某个Consumer.在这篇文章中,我们将会将同一个Message deliver到多个Consumer中.这个模式也被成为 "pub ...
- 柯南君:看大数据时代下的IT架构(6)消息队列之RabbitMQ--案例(Publish/Subscribe起航)
二.Publish/Subscribe(发布/订阅)(using the Java Client) 为了说明这个模式,我们将构建一个简单的日志系统.它将包括两个项目: 第一个将发出日志消息 第二个将接 ...
- RabbitMQ消息队列(四):分发到多Consumer(Publish/Subscribe)
上篇文章中,我们把每个Message都是deliver到某个Consumer.在这篇文章中,我们将会将同一个Message deliver到多个Consumer中.这个模式也被成为 "pub ...
- RabbitMQ 分发到多Consumer(Publish/Subscribe)
上篇文章中,我们把每个Message都是deliver到某个Consumer.在这篇文章中,我们将会将同一个Message deliver到多个Consumer中.这个模式也被成为 "pub ...
- RabbitMQ系列教程之三:发布/订阅(Publish/Subscribe)(转载)
RabbitMQ系列教程之三:发布/订阅(Publish/Subscribe) (本教程是使用Net客户端,也就是针对微软技术平台的) 在前一个教程中,我们创建了一个工作队列.工作队列背后的假设是每个 ...
- RabbitMQ消息队列(四):分发到多Consumer(Publish/Subscribe)[转]
上篇文章中,我们把每个Message都是deliver(提供)到某个Consumer.在这篇文章中,我们将会将同一个Message deliver(提供)到多个Consumer中.这个模式也被成为 & ...
随机推荐
- 用ILSpy查看Session.SessionID的生成算法
缘由 asp.net Session在InProc模式下,容易丢失,经常需要重新登录,且不支持分布式共享. 所以在研究Redis实现原生的Session,本来想用GUID作为key存入cookie,又 ...
- mysql中ip和整数的转换
INET_ATON(expr) 给出一个作为字符串的网络地址的点地址表示,返回一个代表该地址数值的整数.地址可以是4或8比特地址. mysql> SELECT INET_ATON('209.20 ...
- SOUI中做的一个磁力吸附效果
代码见SVN
- iOS中的生命周期
对于一个iOS app来讲,生命周期是一个十分至关重要的东西.对于一个app来讲控制着app的开启.睡眠.关闭等状态:对于一个页面的来讲,控制页面的加载.显示.消失:对于一个View或者一个普通的类来 ...
- 安装sqoop
安装sqoop 1.默认已经安装好java+hadoop 2.下载对应hadoop版本的sqoop版本 3.解压安装包 tar zxvf sqoop-1.4.6.bin__hadoop-2.0.4-a ...
- 识别网络应用所使用的协议Amap
识别网络应用所使用的协议Amap Amap是Kali Linux自带的一款信息收集工具.工作时,它首先向服务器的端口发送内置的触发包(tirgger),然后获取响应.通过分析响应包数据,来识别该端 ...
- linux內核輸出soft lockup
創建的內核線程長期佔用cpu,一直內核認為線程soft lockup,如無法獲取自旋鎖等:因此線程可適度調用schdule(),以進行進程的調度:因為kwatchdog的執行級別低,一直得不到執行 [ ...
- linux查看是什么操作系统是什么命令
https://zhidao.baidu.com/question/361519585968730492.html
- 普林斯顿算法课第五周作业_KdTree
作业地址:http://coursera.cs.princeton.edu/algs4/assignments/kdtree.html 作业难点: 1.如何构建KdTree,使用什么样的数据结构? 根 ...
- 工厂模式模拟Spring的bean加载过程
一.前言 在日常的开发过程,经常使用或碰到的设计模式有代理.工厂.单例.反射模式等等.下面就对工厂模式模拟spring的bean加载过程进行解析,如果对工厂模式不熟悉的,具体可以先去学习一下工厂 ...