Guava的EventBus

Guava的EventBus

一、EventBus介绍和简单实用

EventBus允许发布订阅模式中组建不用明确的注册,就可以相互进行沟通。它专为使用显式注册替换传统的 Java 进程内事件分发而设计。它不是一个通用的发布-订阅系统,也不是用于进程间通信的。

示例:

// 监听者
public class EventBusChangeRecord {
    /**
     * 订阅消息
     * @param changeEvent
     */
    @Subscribe
    public void recordCustomerChange(ChangeEvent changeEvent) {
        System.out.println("Listener: " + changeEvent.getData());
    }
}

// 第二个监听者
public class EventListener02 {

    @Subscribe
    public void run(ChangeEvent changeEvent) {
        System.out.println("run: "+changeEvent.getData());
    }
}
// 主题
public class ChangeEvent {
    private String data;

    public void changeData(String data) {
        this.data = data;
    }

    public String getData() {
        return data;
    }
}
public class EventBusDemo {

    public static void main(String[] args) {
        EventBus eventBus = new EventBus();
        // 注册监听者
        eventBus.register(new EventBusChangeRecord());
        // 注册第二个监听者
        eventBus.register(new EventListener02());

        // 下面的代码必须在是最后调用 post()  方法
        ChangeEvent changeEvent = new ChangeEvent();
        // 改变主题的属性
        changeEvent.changeData("hello, EventBus");
        // 发布主题
        eventBus.post(changeEvent);
        // 改变主题的属性
        changeEvent.changeData("hello, EventBus2");
        eventBus.post(changeEvent);
    }
}
-- 运行上面代码将会输出
Listener: hello, EventBus
run: hello, EventBus
Listener: hello, EventBus2
run: hello, EventBus2

二、将基于EventListener的系统修改为基于EventBus

2.1 对于监听者:Listener

(1)为了监听到特殊类型的事件(例如:CustomerChangeEvent):
  • 在传统的Java事件:实现一个定义了带有事件的接口。例如CustomerChangeEventListener;
  • 使用EventBus:创建一个方法它接收CustomerChangeEvent作为唯一的参数,并在上面用@Subscribe注解修饰;
(2) 向事件生产者注册你的监听器方法
  • 在传统的Java事件:传递你的对象到每个生产者的registerCustomerChangeEventListener方法中。这些方法很少被定义在公共的接口中,因此为了知道每个可能的生产者,你必须知道它们的类型;
  • 使用EventBus:传递你的对象到EventBus的EventBus.register(Object) 方法中。你需要确保你的对象和生产者共享一个EventBus。
(3) 监听公共事件超级类型
  • 在传统的Java事件:不容易
  • 使用EventBus:事件会自动分派给任何超类型的监听器。允许接口类型的监听器或Object的“通配符监听器”。
(4) 监听和探测在没有监听器情况下分派的事件
  • 在传统的Java事件:添加代码到每个事件分发方法(或者使用AOP)
  • 使用EventBus:订阅DeadEvent。EventBus将通知您任何已发布但未交付的事件。

2.2 对于生产者:Producers

(1)为了追踪事件的听众:
  • 在传统的Java事件:写代码管理一个监听器的列表到你的对象中。包含同步,或者使用工具类,像EventListenerList
  • 使用EventBus:EventBus会为你做这些事情。
(2)发布一个事件给监听着
  • 在传统的Java事件:写一个方法发布事件到每一个监听者,包括错误隔离和同步。
  • 使用EventBus:将事件对象传递给EventBus的EventBus.post(Object)方法。

三、词汇表

EventBus系统和代码使用下面的术语讨论事件分发:

事件能够传递到bus到对象
订阅(Subscribing)向EventBus注册监听器行为,以便它的处理程序接收事件。
监听器(Listener)一个希望接收事件的对象,通过暴露处理方法。
处理方法(Handler method)一个公开的方法,EventBus应该用来发布事件。处理程序方法由@Subscribe注解标注
传递一个事件(Posting an event)通过EventBus让事件对任何的监听器管用。

四、常见问题

4.1 为什么必须创建一个自己的EventBus,而不是使用一个单例的

EventBus没有指定如何使用它。没有什么可以阻止你的应用程序为每个组件拥有单独的EventBus实例,或者使用单独的实例来按照上下文或主题来分隔事件。这也使得在测试中设置和拆除 EventBus 对象变得很简单。

当然,如果你想要一个进程范围的 EventBus 单例,没有什么能阻止你这样做。只需让您的容器在全局范围内将 EventBus 创建为单例(或将其存储在静态字段中,如果您喜欢这种情况)。

简而言之,EventBus 不是一个单例,因为我们宁愿不为您做出那个决定。 随心所欲地使用它。

4.2 能否从一个EventBus中注销一个监听者

可以的,使用EventBus.unregister(Object) 方法,但我们发现这很少需要:

  • 大多数侦听器在启动或延迟初始化时注册,并在应用程序的生命周期内持续存在。
  • 范围特定的 EventBus 实例可以处理临时事件分发(例如,在请求范围的对象之间分发事件)
  • 对于测试,EventBus 实例可以轻松创建和丢弃,无需显式注销。

4.3 为什么使用注解标注处理方法,而不是要求监听器实现接口?

我们认为 Event Bus 的 @Subscribe 注释与实现接口一样明确地传达了您的意图(或者可能更明确),同时让您可以自由地将事件处理程序方法放置在您希望的任何位置,并为它们提供意图揭示的名称。

传统的 Java 事件使用侦听器接口,该接口通常只支持少数几种方法——通常是一个。 这有许多缺点:

  • 任何一个类都只能实现对给定事件的单个响应。
  • 侦听器接口方法可能会发生冲突。
  • 该方法必须以事件命名(例如,handleChangeEvent),而不是其目的(例如,recordChangeInJournal)。
  • 每个事件通常都有自己的接口,没有用于一系列事件(例如所有 UI 事件)的公共父接口。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值