11-事件总线

原文链接 译文连接 译者:沈义扬

传统上,Java的进程内事件分发都是通过发布者和订阅者之间的显式注册实现的。设计EventBus就是为了取代这种显示注册方式,使组件间有了更好的解耦。EventBus不是通用型的发布-订阅实现,不适用于进程间通信。

范例

// Class is typically registered by the container.
class EventBusChangeRecorder {
    @Subscribe public void recordCustomerChange(ChangeEvent e) {
        recordChange(e.getChange());
    }
}
// somewhere during initialization
eventBus.register(new EventBusChangeRecorder());
// much later
public void changeCustomer() {
    ChangeEvent event = getChangeEvent();
    eventBus.post(event);
}

一分钟指南

把已有的进程内事件分发系统迁移到EventBus非常简单。

事件监听者[Listeners]

监听特定事件(如,CustomerChangeEvent):

  • 传统实现:定义相应的事件监听者类,如CustomerChangeEventListener;
  • EventBus实现:以CustomerChangeEvent为唯一参数创建方法,并用Subscribe注解标记。

把事件监听者注册到事件生产者:

  • 传统实现:调用事件生产者的registerCustomerChangeEventListener方法;这些方法很少定义在公共接口中,因此开发者必须知道所有事件生产者的类型,才能正确地注册监听者;
  • EventBus实现:在EventBus实例上调用EventBus.register(Object)方法;请保证事件生产者和监听者共享相同的EventBus实例

按事件超类监听(如,EventObject甚至Object):

  • 传统实现:很困难,需要开发者自己去实现匹配逻辑;
  • EventBus实现:EventBus自动把事件分发给事件超类的监听者,并且允许监听者声明监听接口类型和泛型的通配符类型(wildcard,如 ? super XXX)。

检测没有监听者的事件:

  • 传统实现:在每个事件分发方法中添加逻辑代码(也可能适用AOP);
  • EventBus实现:监听DeadEvent;EventBus会把所有发布后没有监听者处理的事件包装为DeadEvent(对调试很便利)。

事件生产者[Producers]

管理和追踪监听者:

  • 传统实现:用列表管理监听者,还要考虑线程同步;或者使用工具类,如EventListenerList;
  • EventBus实现:EventBus内部已经实现了监听者管理。

向监听者分发事件:

  • 传统实现:开发者自己写代码,包括事件类型匹配、异常处理、异步分发;
  • EventBus实现:把事件传递给 EventBus.post(Object)方法。异步分发可以直接用EventBus的子类AsyncEventBus

术语表

事件总线系统使用以下术语描述事件分发: