Google的Guava类库提供了EventBus,用于提供一套组件内publish/subscribe的解决方案.事件总线EventBus,用于管理事件的注册和分发。在系统中,Subscribers会向EventBus注册自己感兴趣的事件,而publishers会将自己产生的事件发布给EventBus。在系统中,EventBus事件分发默认设置为串行的(可设置),我们在Subscribers中的事件处理速度要快,不要阻塞当前的事件纷发进程。
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"); }
post一个事件很简单,只需要调用EventBus.post方法即可以实现。EventBus会调用Subscriber的handler method处理事件对象。
方法接受一个事件类型对象,当publisher发布一个事件,eventbus会串行的处理event-handling method, 所以我们需要让event-handing method处理的速度快一些,通常我们可以通过多线程手段来解决延迟的问题。
(replace @Subscribe标签),我们认为handler Method是线程安全的。
例子中,我们使用cookie店为例,为了简单起见,系统中只定义了五个对象:
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 { }
@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
修改Handler method接口,
public interface HandlerService { @AllowConcurrentEvents void handler(EmptyEvent emptyEvent); }
测试代码和串行代码一致,测试结果如下所示,事件发布耗时只需1ms
retrieve a cookie retrieve a cookie retrieve a cookie =======触发事件发布============ Publishing event time: 1 ms
本文讲解了如何使用Guava的EventBus来构建publish/subscribe系统,分别给出了串行和并行发布的使用方法,希望能够给读者带来一些帮助和启发。