使用 guava 工具,先在 pom 中引入依赖:https://mvnrepository.com/artifact/com.google.guava/guava/
1 | <dependency> |
Guava EventBus 的使用
简单使用
先编写监听者:
1 | import com.google.common.eventbus.Subscribe; |
再创建 EventBus 对象,将上述监听者注册到 EventBus 对象实例中,调用 post() 发送消息即可:
1 | import com.google.common.eventbus.EventBus; |
EventBus 构造函数中,如果不显示指定名称,则使用:default 作为默认名称。
注意:消息类型必须是包装类型,不能是基本数据类型。
多个监听者存在继承关系
当只注册监听器中的父类中也监听了某些消息的时候,父类的监听方法也会执行。如果父类的监听方法被子类覆盖监听,则只执行子类监听器的方法。
类监听器:
1 | import com.google.common.eventbus.Subscribe; |
子类监听器:
1 | import com.google.common.eventbus.Subscribe; |
注册监听器并发送消息:
1 | import com.google.common.eventbus.EventBus; |
日志输出:
1 | ChildListener.accept, event = this message from eventBus |
多个事件存在继承关系
event 如果有父类,此时某个监听器监听的event是这个基类,那么消息是这个子类的时候,该监听父类的监听器方法也会执行。
父类事件对象:
1 | import com.google.gson.Gson; |
子类事件对象:
1 | import com.google.gson.Gson; |
监听器对象:
1 | import com.google.common.eventbus.Subscribe; |
单元测试:
1 | import com.google.common.eventbus.EventBus; |
日志输出:
1 | SimpleListener.acceptAppleEvent => appleEvent {"name":"apple"} |
异常处理
多个监听器同时监听相同消息,其中一个监听器有异常,那么不会影响其他监听器消费消息。可以在EventBus构造函数中传入一个异常处理器,当监听器有异常抛出时,会执行这个异常处理器。
思考点:如果异常处理很长时间,会不会导致后面的监听器等待执行?
异常处理器:
1 | import com.google.common.base.Throwables; |
监听器对象:
1 | import com.google.common.eventbus.Subscribe; |
单元测试:
1 | import com.google.common.eventbus.EventBus; |
日志输出:
1 | MyListener.method2 => 2147483647 |
DeadEvent 实现类型
监听器监听 DeadEvent 类型事件:
1 | import com.google.common.eventbus.DeadEvent; |
单元测试:
1 | import com.google.common.eventbus.EventBus; |
日志输出:
1 | DeadEventListener.handle deadEvent => DeadEvent{source=EventBus{DEAD-EVENT-BUS}, event=message} |
自实现 EventBus
Bus 接口设计
自己实现一个 EventBus 前需要先设计好需要多少功能,即多核心少接口:将监听者注册bus,将监听者从bus中移除,发送消息,发送带有主题的消息,获取当前 bus 名称等:
1 | /** |
Bus 接口实现
实现 Bus 接口,重要的是怎么来保存注册到中的监听者,怎么在消息发布者调用 post() 发布消息的时候,根据消息的类型找到对应的要监听的方法并执行,如果有异常处理器,则执行异常处理器。
MyEventBus 实现 MyBus 接口,在其类中增加以下属性:MyEventBus 的构造函数仅仅是设置属性的入口,消息存储和消息消费,均由 MyRegistry 和 MyDispatcher 来执行。
1 | public class MyEventBus implements MyBus { |
Dispatcher 实现
Dispatcher 用于执行消息消费,因此对于 Dispatcher,它需要直到要消费的消息信息及异常处理器:
1 | import java.lang.reflect.Method; |
MyRegistry 实现
1 | import java.lang.reflect.Method; |
EventExceptionHandler 异常处理器
当有异常发生时,用户可以自己实现异常处理器接口,当有异常发生时会回调该接口:
1 | /** |
消息上下文对象
异常产生,需要告知消费者,产生异常的相关上下文:
1 | import java.lang.reflect.Method; |
Subscribe 监听器注解
监听器注解用于标记要监听并执行的方法:
1 | /** |
监听者信息对象
为了便于管理监听者对象,需要对监听者的信息进行封装,并存储到 MyRegistry 的 ConcurrentHashMap<> 容器中:
1 | import java.lang.reflect.Method; |
小结
自实现一个简单的 EventBus,要涉及到以下核心组件:
核心接口
MyBus
通过构造器接收监听者(使用 @MySubscribe 注解了某些方法)和自定义异常处理器(自实现了 MyEventExceptionHandler 接口)
MyEventExceptionHandler
用于消息过程出现异常时,处理异常
MyEventContext
异常处理过程中,将产生异常的数据封装起来
核心类
MyEventBus
MyBus 接口的实现类,其内部维护了 MyDispatcher 和 MyRegistry。
MyDispatcher
用于真正指定消费逻辑,内部维护了 MyEventExceptionHandler 实现(从 MyEventBus 构造器传入的)。
MyRegistry
用于对所有加了 @MySubscribe 注解的监听者信息进行管理,包括注册和注销。
MySubscriber
对注册的监听者信息进行封装,方便 MyRegistry 存储,也方便 MyDispatcher 消费执行。
核心注解
MySubscribe
提供要监听消息的方法注解标记。