使用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中.这个模式也被成为 & ...
随机推荐
- 【Java EE 学习 71 下】【数据采集系统第三天】【分析答案实体】【删除问题】【删除页面】【删除调查】【清除调查】【打开/关闭调查】
一.分析答案实体 分析答案实体主要涉及到的还是设计上的问题,技术点几乎是没有的.首先需要确定一下答案的格式才能最终确定答案实体中需要有哪些属性. 答案格式的设计是十分重要的,现设计格式如下: 在表单中 ...
- GruntJS学习(转)
GruntJS 是基于JavaScript的命令行构建工具,它可以帮助开发者们自动化重复性的工作.你可以把它看成是JavaScript下的Make或者Ant.它可以完成诸如精简.编译.单元测试.lin ...
- 在Linux和Windows的Docker容器中运行ASP.NET Core
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 译者序:其实过去这周我都在研究这方面的内容,结果周末有事没有来得及总结为文章,Scott H ...
- 学习微信小程序之css12设置盒子内容的宽高
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Nginx - Windows下作为服务启动
Nginx官方没有提供作为服务启动nginx的方案.以服务启动nginx依赖于winsw,当前最新版是1.19. 参考:https://segmentfault.com/a/1190000006807 ...
- iOS how to stop a scrolling scrollView
- (void)killScroll { CGPoint offset = scrollView.contentOffset; offset.y -= 1.0; [scrollView setCont ...
- Struts相关
使用Struts2流程: 1.导入Struts2类包 2.在Web源代码文件夹中,创建名为struts.xml的配置文件.在其中定义Action对象,其关键代码如下: struts.xml: < ...
- android 5.0以上通知栏、状态栏图标变成白色
在5.0以上的系统上发现,平常的自定义notification出来的icon,居然在状态栏上变成了纯白色的icon. 看源代码会发现: protected void applyColorsAndBac ...
- 支持“ApplicationDbContext”上下文的模型已在数据库创建后发生更改
异常信息 解决方法: 1.PM> Enable-Migrations 2.打开生成的Configuration.cs文件,修改代码如下 public Configuration() { Auto ...
- VS2015 调试时 编辑并继续不可用
最近在项目中遇到一次调试时 编辑并继续不可用.结合网上说的工具->设置->调试->常规下的一些操作,到后来还是不可用,最后把项目的解决方案平台改成Mixed Platform ,之后 ...