如何修改Guava中Eventbus分发器Dispatcher

背景

Guava中Eventbus有三种不同的分发器:PerThreadQueuedDispatcher、LegacyAsyncDispatcher、ImmediateDispatcher,默认使用PerThreadQueuedDispatcher,而Guava中无法显式修改分发器,那么要想使用其它分发器该如何做呢?

三种分发器区别

Eventbus分发器顶层接口Dispatcher,Dispatcher接口有三个实现类

  1. PerThreadQueuedDispatcher

PerThreadQueuedDispatcher是类似广度优先方式分发事件,例如代码中发布了事件A,订阅者收到后,在执行过程中又发布了事件B和事件C,PerThreadQueuedDispatcher会确保事件A分发给所有订阅者后,再分发B、C事件。

  1. ImmediateDispatcher

ImmediateDispatcher是类似深度优先方式分发事件,在发布事件时立即将事件分发给订阅者,而不使用中间队列更改分发顺序。

  1. 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;
}

扩展

  1. 除Guava的eventbus外,也可以使用Spring的事件机制ApplicationEventPublisher,会比Guava的eventbus提供更多的能力以及更适配spring框架,参考:juejin.cn/post/714084...
相关推荐
成年老猿3 个月前
Guava-EventBus 源码解析
java·guava·eventbus
SuperHeroWu74 个月前
【HarmonyOS】应用通知广播的使用
华为·harmonyos·鸿蒙·openharmony·eventbus·广播·eventhub
xiangxiongfly9156 个月前
Android Kotlin版封装EventBus
android·kotlin·eventbus
漂流瓶jz7 个月前
Vue中的事件总线(EventBus)是什么?它有什么优点和缺点?
前端·javascript·vue.js·eventbus·事件总线
asyncrustacean7 个月前
用一行代码监听 Web Element 的所有事件,ocev.js 介绍
typescript·github·eventbus
还是大剑师兰特8 个月前
069:vue中EventBus的使用方法(图文示例)
vue.js·eventbus·eventbus使用方法
川峰9 个月前
【React系列】非父子组件通信—Context.Provider共享数据、events库事件总线通信
react·context·eventbus·非父子组件通信·provider
摸鱼小小虫9 个月前
【EventBus】EventBus源码浅析
android·java·eventbus
德莱厄斯10 个月前
发布订阅:用 pinia 实现全局无缝通信
vue.js·vuex·eventbus