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 事件)的公共父接口。
### Google Guava EventBus 库文档与使用示例 #### 简介 Guava 的 `EventBus` 是一种发布-订阅模式的事件总线实现,允许组件之间解耦通信。通过定义事件类并注册监听器来处理这些事件,可以简化应用程序内部的消息传递机制[^1]。 #### 基本概念 - **事件 (Events)**: 表示应用内发生的特定情况的对象实例。 - **监听者 (Listeners)**: 实现方法响应某些类型的事件对象。 - **发布者 (Publisher)**: 负责创建并向 `EventBus` 发布新事件实例的实体。 - **订阅者 (Subscriber)**: 注册到 `EventBus` 上以接收感兴趣类型事件的方法或函数。 #### 使用说明 ##### 创建和配置 `EventBus` ```java // 初始化一个新的 EventBus 对象 EventBus eventBus = new EventBus(); ``` ##### 定义事件类 ```java public class MyCustomEvent { private final String message; public MyCustomEvent(String msg) { this.message = msg; } @Override public String toString() { return "MyCustomEvent{" + "message='" + message + '\'' + '}'; } } ``` ##### 编写监听者逻辑 ```java public class EventListener { // 订阅该事件的方法名前需加上@Subscribe注解 @Subscribe public void handleMyCustomEvent(MyCustomEvent event){ System.out.println("Received custom event:" +event); } } ``` ##### 将监听者注册至 `EventBus` ```java EventListener listenerInstance = new EventListener(); // 向 EventBus 中添加监听者 eventBus.register(listenerInstance); ``` ##### 发送事件给所有已注册的监听者 ```java // 构造一个自定义事件实例 MyCustomEvent myEvent = new MyCustomEvent("Hello, world!"); // 通过调用 post 方法向所有的监听者广播此事件 eventBus.post(myEvent); ``` 以上就是如何利用 Guava 提供的 `EventBus` 来构建松散耦合的应用程序模块间通讯的方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值