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事件

  1. Subsciber对象需要定义handler method,用于接受并处理一个通知事件对象
  2. 使用Subscribe标签标识事件handler method
  3. 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店为例,为了简单起见,系统中只定义了五个对象:

  1. EmptyEvent对象:用于表明CookieContaier cookie数量为0
  2. CookieContaier对象:用于Cookie的存储,当cookie数量为0时,会发布EmptyEvent事件
  3. CookieSeller: EmptyEvent事件订阅者
  4. CookieMailBoss:EmptyEvent事件订阅者
  5. 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系统的更多相关文章

  1. 设计模式:Observer(观察者)—— Guava EventBus

    本文分为三个部分:   Observer(观察者) Guava EventBus详解 Guava EventBus使用示例   1. Observer(观察者)   1.1 背景   我们设计系统时, ...

  2. 【RabbitMQ】Publish/Subscribe

    Publish/Subscribe 在上一节我们创建了一个work queue.背后的设想为每个任务被分发给明确的消费者.这节内容我们将做一些完全不同的事情 -- 我们将发送一条消息给多个消费者.这种 ...

  3. RabbitMQ学习总结 第四篇:发布/订阅 Publish/Subscribe

    目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...

  4. (转)RabbitMQ消息队列(四):分发到多Consumer(Publish/Subscribe)

    上篇文章中,我们把每个Message都是deliver到某个Consumer.在这篇文章中,我们将会将同一个Message deliver到多个Consumer中.这个模式也被成为 "pub ...

  5. 柯南君:看大数据时代下的IT架构(6)消息队列之RabbitMQ--案例(Publish/Subscribe起航)

    二.Publish/Subscribe(发布/订阅)(using the Java Client) 为了说明这个模式,我们将构建一个简单的日志系统.它将包括两个项目: 第一个将发出日志消息 第二个将接 ...

  6. RabbitMQ消息队列(四):分发到多Consumer(Publish/Subscribe)

    上篇文章中,我们把每个Message都是deliver到某个Consumer.在这篇文章中,我们将会将同一个Message deliver到多个Consumer中.这个模式也被成为 "pub ...

  7. RabbitMQ 分发到多Consumer(Publish/Subscribe)

    上篇文章中,我们把每个Message都是deliver到某个Consumer.在这篇文章中,我们将会将同一个Message deliver到多个Consumer中.这个模式也被成为 "pub ...

  8. RabbitMQ系列教程之三:发布/订阅(Publish/Subscribe)(转载)

    RabbitMQ系列教程之三:发布/订阅(Publish/Subscribe) (本教程是使用Net客户端,也就是针对微软技术平台的) 在前一个教程中,我们创建了一个工作队列.工作队列背后的假设是每个 ...

  9. RabbitMQ消息队列(四):分发到多Consumer(Publish/Subscribe)[转]

    上篇文章中,我们把每个Message都是deliver(提供)到某个Consumer.在这篇文章中,我们将会将同一个Message deliver(提供)到多个Consumer中.这个模式也被成为 & ...

随机推荐

  1. 动态规划求最长公共子序列(Longest Common Subsequence, LCS)

    1. 问题描述 子串应该比较好理解,至于什么是子序列,这里给出一个例子:有两个母串 cnblogs belong 比如序列bo, bg, lg在母串cnblogs与belong中都出现过并且出现顺序与 ...

  2. Ubuntu菜鸟入门(八)—— QQ安装

    一.下载 http://www.ubuntukylin.com/application/show.php?lang=cn&id=279 二.安装流程 1.解压,到解压文件夹中运行 sudo d ...

  3. linux系统swappiness参数在内存与交换分区间优化

    http://blog.itpub.net/29371470/viewspace-1250975        swappiness的值的大小对如何使用swap分区是有着很大的联系的.swappine ...

  4. PHP常用函数、数组方法

    常用函数:rand(); 生成随机数rand(0,50); 范围随机数时间:time(); 取当前时间戳date("Y-m-d H:i:s"); Y:年 m:月份 d:天 H:当前 ...

  5. 高效快捷实用移动开单手持扫描打印一体智能 POS PDA

    PDA数据采集器,是一款移动手持开单设备,它通过WIFI和GPRS连接并访问电脑,从进销存软件中读取数据,实现移动开单,打破电脑开单模式. 它自带扫描器,可直接扫描条码来查找产品,且功能强大.操作简单 ...

  6. 运行时使用Dev的ImageListEditor

    uses cxImageListEditor, cxGridMenuOperations; {$R *.dfm} procedure TForm1.Btn1Click(Sender: TObject) ...

  7. MVC5项目中添加Wep API

    一.查看MVC版本,决定你有没有必要看这篇文章 打开web.config,看到以下内容 <dependentAssembly> <assemblyIdentity name=&quo ...

  8. Codeforces Round #366 (Div. 2)

    CF 复仇者联盟场... 水题 A - Hulk(绿巨人) 输出love hate... #include <bits/stdc++.h> typedef long long ll; co ...

  9. Canvas 最佳实践(性能篇)

    Canvas 想必前端同学们都不陌生,它是 HTML5 新增的「画布」元素,允许我们使用 JavaScript 来绘制图形.目前,所有的主流浏览器都支持 Canvas. Canvas 最常见的用途是渲 ...

  10. Linux下Electron的Helloworld

    什么是Electron Electron 框架的前身是 Atom Shell,可以让你写使用 JavaScript,HTML 和 CSS 构建跨平台的桌面应用程序.它是基于io.js 和 Chromi ...