背景
Guava中Eventbus有三种不同的分发器:PerThreadQueuedDispatcher、LegacyAsyncDispatcher、ImmediateDispatcher,默认使用PerThreadQueuedDispatcher,而Guava中无法显式修改分发器,那么要想使用其它分发器该如何做呢?
三种分发器区别
Eventbus分发器顶层接口Dispatcher,Dispatcher接口有三个实现类
- PerThreadQueuedDispatcher
PerThreadQueuedDispatcher
是类似广度优先方式分发事件,例如代码中发布了事件A,订阅者收到后,在执行过程中又发布了事件B和事件C,PerThreadQueuedDispatcher会确保事件A分发给所有订阅者后,再分发B、C事件。
- ImmediateDispatcher
ImmediateDispatcher
是类似深度优先方式分发事件,在发布事件时立即将事件分发给订阅者,而不使用中间队列更改分发顺序。
- LegacyAsyncDispatcher
LegacyAsyncDispatcher有一个全局队列用于存放所有事件,LegacyAsyncDispatcher特性与AsyncEventBus特性完全相符,此分发器常用于AsyncEventBus异步事件总线中。
我们需要根据场景实际选择合适的分发器
如何修改分发器 - 反射利器
Guava中EventBus未提供可以指定分发器的构造函数,具体EventBus类中构造函数如下:
scss
public EventBus() {
this("default");
}
public EventBus(String identifier) {
this(
identifier,
MoreExecutors.directExecutor(),
Dispatcher.perThreadDispatchQueue(),
LoggingHandler.INSTANCE);
}
public EventBus(SubscriberExceptionHandler exceptionHandler) {
this(
"default",
MoreExecutors.directExecutor(),
Dispatcher.perThreadDispatchQueue(),
exceptionHandler);
}
EventBus(
String identifier,
Executor executor,
Dispatcher dispatcher,
SubscriberExceptionHandler exceptionHandler) {
this.identifier = checkNotNull(identifier);
this.executor = checkNotNull(executor);
this.dispatcher = checkNotNull(dispatcher);
this.exceptionHandler = checkNotNull(exceptionHandler);
}
有人向guava官方提过该问题(支持多种分发器,但却不提供相应的构造函数或方法以便修改),可官方回复eventbus已经不维护,未来不会处理此问题。
那我们要想修改该如何做呢? ------ 反射
如下代码,通过反射机制可以修改eventbus的分发器
ini
@Bean("wsEventBus")
public EventBus wsEventBus() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
InvocationTargetException, InstantiationException, NoSuchFieldException {
Class<?> privateClass = Class.forName("com.google.common.eventbus.Dispatcher$ImmediateDispatcher");
Constructor<?> constructor = privateClass.getDeclaredConstructor();
constructor.setAccessible(true);
Object instance = constructor.newInstance();
EventBus eventBus = new EventBus(new MyExceptionHandler());
Class<?> myClass = EventBus.class;
// 获取私有字段
Field dispatcher = myClass.getDeclaredField("dispatcher");
dispatcher.setAccessible(true);
dispatcher.set(eventBus, instance);
return eventBus;
}
扩展
- 除Guava的eventbus外,也可以使用Spring的事件机制ApplicationEventPublisher,会比Guava的eventbus提供更多的能力以及更适配spring框架,参考:juejin.cn/post/714084...