EventBus原理深度解析

  1. 云栖社区>
  2. Java架构沉思录>
  3. 博客>
  4. 正文

EventBus原理深度解析

技术小能手 2018-10-24 16:28:09 浏览1556
展开阅读全文

一、问题描述

在工作中,经常会遇见使用异步的方式来发送事件,或者触发另外一个动作:经常用到的框架是MQ(分布式方式通知)。如果是同一个jvm里面通知的话,就可以使用EventBus。由于EventBus使用起来简单、便捷,因此,工作中会经常用到。深入理解该框架的原理就很有必要。

二、框架解析

2.1、组织结构

eventbus的组织结构如下:

6b2b40f15aacd7afac3b6f231cf4e00c5e408dc0

eventbus主要有以下几部分组成:

1、eventbus、asyncEventBus:事件发送器。

2、event:事件承载单元。

3、SubscriberRegistry:订阅者注册器,将订阅者注册到event上,即将有注解Subscribe的方法和event绑定起来。

4、Dispatcher:事件分发器,将事件的订阅者调用来执行。

5、Subscriber、SynchronizedSubscriber:订阅者,并发订阅还是同步订阅。

2.2、运行原理

1、eventbus是基于注册监听的方式来运行的,因此,首先需要将eventbus,然后才会有事件及监听者。新建eventbus或者AsyncEventBus的方式如下:

8bc533aea382625ab9b09d46436ae2e3c17d12c9

或者

5b7a0f1554cadab3b546592dbfb716b4535b5fa2

2、注册监听者。

b7fff99e177760e21eb4c8bb74455830bff86a8a

底层就是将类eventListener中所有注解有Subscribe的方法与其Event对放在一个map中(一个event可以对应多个Subscribe的方法)。实现如下:

15e2a5316aa4910878604729343ec8ffda310052

3、事件发送:执行指定事件类型的订阅者(包含了method),从订阅者中获取指定事件的订阅者,然后按照规则(同步、异步)执行指定的方法。

4e8fd75869d9a2b87b6246f4385fa110e837e646

上述代码说明,如果事件没有监听者,就当作死亡事件来对待。

a01b0cab0fad04cc7ef64667d5685897a5e907b8

这里就说明,最后就是被订阅的方法被调用。

4、EventBus与AsyncEventBus的区别

从字面上看,AsyncEventBus是异步的EventBus,那么EventBus应该就是同步的了。EventBus的executor为MoreExecutors.directExecutor(),其实现如下:

ba916ed21177d71ac30b5ac9465374aacaf66142

其execute方法直接执行线程的run方法,即同步调用run方法执行。EventBus的dispatcher为PerThreadQueuedDispatcher。其dispatch方法如下:

7d1f763761d920d4b723272b14fc5ce785e9584e

dispatchEvent的实现如下:

e31c3638585543ac6ab9de7f908a145cbed1e25e

因此,整个执行过程如下:

6231694336c566e1c47453580973290b5cd8d843

整个过程都是同步方式执行,因此,EventBus是同步的。

AsyncEventBus的dispatcher为LegacyAsyncDispatcher,executor为自己指定的线程池。运行流程如下:

5f0aa0bf8c32df4403ed58f0885996ff8d2a069f

虚线为线程池异步调度,因此,AsyncEventBus为异步方式。

5、AllowConcurrentEvents的作用

它所在的代码为:

25fab7f106bd7374c6da9e4de038f3c97f6bd3ad

即如果订阅者方法上有注解AllowConcurrentEvents,则返回Subscriber,否则,返回SynchronizedSubscriber。SynchronizedSubscriber的字面意思为同步订阅者,它的实现代码为:

915f18fffcb19d9135d3290ed4f0edb35e4fd7e4

即没有使用注解AllowConcurrentEvents的订阅者,在并发环境中,都是串行执行。这在高并发环境中,会严重影响性能。

三、使用案例

a4887a72ff2462e1f79a58cb5874f179d88826b8

四、注意事项

1、在高并发的环境下使用AsyncEventBus时,发送事件可能会出现异常,因为它使用的线程池,当线程池的线程不够用时,会拒绝接收任务,就会执行线程池的拒绝策略,如果需要关注是否提交事件成功,就需要将线程池的拒绝策略设为抛出异常,并且try-catch来捕获异常。如下:

22884e7809db6161aaf6b9a6f81b1e0dbf8d1668

2、本文用到的guava版本如下:

4dd10760429f550a9105042b1e58cb0a1fefeaa7

原文发布时间为:2018-10-24
本文作者:yangjianzhou
本文来自云栖社区合作伙伴“Java架构沉思录”,了解相关信息可以关注“Java架构沉思录”。

网友评论

登录后评论
0/500
评论
技术小能手
+ 关注
所属团队号: Java架构沉思录