JAVA | Guava EventBus 使用

系列文章目录

Table of Contents

[TOC]

前言

EventBus 是 Guava 的事件处理机制,是观察者模式(生产/消费模型)的一种实现。

观察者模式在我们日常开发中使用非常广泛,例如在订单系统中,订单状态或者物流信息的变更会向用户发送APP推送、短信、通知卖家、买家等等;审批系统中,审批单的流程流转会通知发起审批用户、审批的领导等等。

Observer模式也是 JDK 中自带就支持的,其在 1.0 版本就已经存在 Observer,不过随着 Java 版本的飞速升级,其使用方式一直没有变化,许多程序库提供了更加简单的实现,例如 Guava EventBus、RxJava、EventBus 等

一、为什么要用 Observer模式以及 EventBus 优点 ?

EventBus 优点相比 Observer 编程简单方便

通过自定义参数可实现同步、异步操作以及异常处理

单进程使用,无网络影响

缺点只能单进程使用

项目异常重启或者退出不保证消息持久化

如果需要分布式使用还是需要使用 MQ

二、EventBus 使用步骤

1. 引入库

Gradlecompile group: 'com.google.guava', name: 'guava', version: '29.0-jre'

Maven

com.google.guava

guava

29.0-jre

引入依赖后,这里我们主要使用 com.google.common.eventbus.EventBus 类进行操作,其提供了 register、unregister、post 来进行注册订阅、取消订阅和发布消息public void register(Object object);

public void unregister(Object object);

public void post(Object event);

2. 同步使用

1. 首先创建一个 EventBusEventBus eventBus = new EventBus();

2. 创建一个订阅者

在 Guava EventBus 中,是根据参数类型进行订阅,每个订阅的方法只能由一个参数,同时需要使用 @Subscribe 标识class EventListener {

/**

* 监听 Integer 类型的消息

*/

@Subscribe

public void listenInteger(Integer param) {

System.out.println("EventListener#listenInteger ->" + param);

}

/**

* 监听 String 类型的消息

*/

@Subscribe

public void listenString(String param) {

System.out.println("EventListener#listenString ->" + param);

}

}

3. 注册到 EventBus 上并发布消息EventBus eventBus = new EventBus();

eventBus.register(new EventListener());

eventBus.post(1);

eventBus.post(2);

eventBus.post("3");

运行结果为EventListener#listenInteger ->1

EventListener#listenInteger ->2

EventListener#listenString ->3

根据需要我们可以创建多个订阅者完成订阅信息,同时如果一个类型存在多个订阅者,则所有订阅方法都会执行

为什么说这么做是同步的呢?

Guava Event 实际上是使用线程池来处理订阅消息的,通过源码可以看出,当我们使用默认的构造方法创建 EventBus 的时候,其中 executor 为 MoreExecutors.directExecutor(),其具体实现中直接调用的 Runnable#run 方法,使其仍然在同一个线程中执行,所以默认操作仍然是同步的,这种处理方法也有适用的地方,这样既可以解耦也可以让方法在同一个线程中执行获取同线程中的便利,比如事务的处理

EventBus 部分源码public class EventBus {

private static final Logger logger = Logger.getLogger(EventBus.class.getName());

private final String identifier;

private final Executor executor;

private final SubscriberExceptionHandler exceptionHandler;

private final SubscriberRegistry subscribers;

private final Dispatcher dispatcher;

public EventBus() {

this("default");

}

public EventBus(String identifier) {

this(identifier, MoreExecutors.directExecutor(), Dispatcher.perThreadDispatchQueue(), EventBus.LoggingHandler.INSTANCE);

}

public EventBus(SubscriberExceptionHandler exceptionHandler) {

this("default", MoreExecutors.directExecutor(), Dispatcher.perThreadDispatchQueue(), exceptionHandler);

}

EventBus(String identifier, Executor executor, Dispatcher dispatcher, SubscriberExceptionHandler exceptionHandler) {

this.subscribers = new SubscriberRegistry(this);

this.identifier = (String)Preconditions.checkNotNull(identifier);

this.executor = (Executor)Preconditions.checkNotNull(executor);

this.dispatcher = (Dispatcher)Preconditions.checkNotNull(dispatcher);

this.exceptionHandler = (SubscriberExceptionHandler)Preconditions.checkNotNull(exceptionHandler);

}

}

DirectExecutor 部分源码enum DirectExecutor implements Executor {

INSTANCE;

private DirectExecutor() {

}

public void execute(Runnable command) {

command.run();

}

public String toString() {

return "MoreExecutors.directExecutor()";

}

}

3. 异步使用

通过上面的源码,可以看出只要将构造方法中的 executor 换成一个线程池实现即可, 同时 Guava EventBus 为了简化操作,提供了一个简化的方案即 AsyncEventBusEventBus eventBus = new AsyncEventBus(Executors.newCachedThreadPool());

这样即可实现异步使用

AsyncEventBus 源码public class AsyncEventBus extends EventBus {

public AsyncEventBus(String identifier, Executor executor) {

super(identifier, executor, Dispatcher.legacyAsync(), LoggingHandler.INSTANCE);

}

public AsyncEventBus(Executor executor, SubscriberExceptionHandler subscriberExceptionHandler) {

super("default", executor, Dispatcher.legacyAsync(), subscriberExceptionHandler);

}

public AsyncEventBus(Executor executor) {

super("default", executor, Dispatcher.legacyAsync(), LoggingHandler.INSTANCE);

}

}

4. 异常处理

如果处理时发生异常应该如何处理? 在看源码中,无论是 EventBus 还是 AsyncEventBus 都可传入自定义的 SubscriberExceptionHandler 该 handler 当出现异常时会被调用,我可可以从参数 exception 获取异常信息,从 context 中获取消息信息进行特定的处理

其接口声明为public interface SubscriberExceptionHandler {

/** Handles exceptions thrown by subscribers. */

void handleException(Throwable exception, SubscriberExceptionContext context);

}

总结

在上面的基础上,我们可以定义一些消息类型来实现不同消息的监听和处理,通过实现 SubscriberExceptionHandler 来处理异常的情况,无论时同步还是异步都能游刃有余

参考

java guava eventbus_JAVA | Guava EventBus 使用相关推荐

  1. Google guava 事件总线 EventBus 进程内消息队列

    Google guava 事件总线 EventBus 创建事件总线流程 码代码 引入依赖 一个简单的事件处理 监听者 创建事件生产者总线.注册事件监听者.发送事件 运行结果 扩展 多个事件监听者加De ...

  2. Guava包学习--EventBus

    之前没用过这个EventBus,然后看了一下EventBus的源码也没看明白,(-__-)b.反正大概就是弄一个优雅的方式实现了观察者模式吧.慢慢深入学习一下. 观察者模式其实就是生产者消费者的一个变 ...

  3. Java工具库Guava的区间(范围Range)的构建、区间运算、查询运算、关系运算(包含、相连、交集、并集)的使用示例

    场景 Java核心工具库Guava介绍以及Optional和Preconditions使用进行非空和数据校验: Java核心工具库Guava介绍以及Optional和Preconditions使用进行 ...

  4. 从Java future 到 Guava ListenableFuture实现异步调用

    本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/51232004 前言 随着移动互联网的蓬勃发展,手机App层 ...

  5. 从Java Future 到 Guava ListenableFuture实现异步非阻塞调用

    前言 随着移动互联网的蓬勃发展,手机App层出不穷,其业务也随之变得错综复杂.针对于开发人员来说,可能之前的一个业务只需要调取一次第三方接口以获取数据,而如今随着需求的增加,该业务需调取多个不同的第三 ...

  6. Java类库Google Guava学习

    参考 官网 https://github.com/google/guava Google Guava官方教程(中文版) | 并发编程网 – ifeve.com 一篇让你熟练掌握Google Guava ...

  7. Guava 系列 - Guava基础

    文章目录 Guava 系列 - Guava基础 1.是什么 2.如何构建 3.用户文档 4.为什么选择使用guava Guava 系列 - Guava基础 1.是什么 guava 是一个开源的java ...

  8. guava之guava cache

    一说到缓存,有没有脑海里立马想到的是guava cache.ehcache.redis.memerycache等等这些和缓存相关的技术实现,计算机专业出生可能还会想到cpu的一级缓存.二级缓存.三级缓 ...

  9. [Google Guava] 排序: Guava强大的”流畅风格比较器”

    原文链接 译者: 沈义扬 排序器[Ordering]是Guava流畅风格比较器[Comparator]的实现,它可以用来为构建复杂的比较器,以完成集合排序的功能. 从实现上说,Ordering实例就是 ...

最新文章

  1. 一个妹子的美团面试经历,历经 4 轮 2 小时,成功拿到 Offer
  2. 前端开发工具 vscode 使用技巧篇:控制台由powershell切换为cmd方法,windows下新旧版控制台cmd与powershell互切方法
  3. js---BOW---页面打开方式,跳转方式 2017-03-24
  4. 使用EL表达式接收url的传值
  5. c 语言epc编码如何解开,EPC编码结构
  6. makefile工作笔记0001---认识使用makefile
  7. 2013蓝桥杯C++B:高斯日记;马虎的算式(2种解法)
  8. Redhat Linux Enterprise Server 5.5 x86_64位操作系统Karachi时区问题?
  9. cmd imp导入dmp文件_在cmd中怎么样导入dmp文件?
  10. 鸡兔同笼html语言,鸡兔同笼有哪五种方法
  11. jquery蔚蓝网总结三个页面
  12. 使用计算机用眼卫生,眼睛干涩要注意用眼卫生 缓解眼睛干涩推荐4款花茶
  13. 微信小程序断网异常处理
  14. php deel views,视图 - Views
  15. 单片机什么叫位寻址?/不可位寻址?
  16. 启动虚拟机,电脑蓝屏强制自动重启问题解决
  17. 浅析超启发式算法(hyper heuristic)
  18. hashMap的遍历方式
  19. 获取客户端mac地址 php,js获取客户端mac地址的方法
  20. 删除右键打开IntelliJ IDEA

热门文章

  1. 助力ssr,使用concent为nextjs应用加点料
  2. JAXB Simple Example
  3. 图形推理1000题pdf_小学三年级逻辑推理题,学霸1分钟能做对4题,最后一题难坏家长...
  4. 六,bindings
  5. 合工大计算机组成原理ppt,合工大 计算机组成原理 计算机组成原理提纲.pdf
  6. 深度学习 - 胶囊网络
  7. 数据结构------最短路弗洛伊德算法(Flody)
  8. 小青蛙、花岗岩和南瓜
  9. 【论文阅读】Embracing Domain Differences in Fake News: Cross-domain Fake News Detection using 多模态数据
  10. 如何在表格数据中加同一个数_怎么在excel表格中的数字前统一加一个字母