前言

EventBus的核心思想是观察者模式 (生产/消费者编程模型) 。

通过前面的文章我们已经知道,如何使用eventBus了。我们需要先定义一个Observer(前文中的EventListener类),然后将其注册到eventBus里,通过 @Subscribe 定义消息回调函数。

那我们先看看register(Object object) 和unregister(Object object) 方法。

register (Object object) 解析

public void register(Object object) {

Multimap, EventSubscriber> methodsInListener =

finder.findAllSubscribers(object);

subscribersByTypeLock.writeLock().lock();

try {

subscribersByType.putAll(methodsInListener);

} finally {

subscribersByTypeLock.writeLock().unlock();

}

}

1

2

3

4

5

6

7

8

9

10

publicvoidregister(Objectobject){

Multimap,EventSubscriber>methodsInListener=

finder.findAllSubscribers(object);

subscribersByTypeLock.writeLock().lock();

try{

subscribersByType.putAll(methodsInListener);

}finally{

subscribersByTypeLock.writeLock().unlock();

}

}

可以看到是先通过SubscriberFindingStrategy接口里的findAllSubscribers方法获取所有标记了@ Subscribe 注解的方法,其中该接口的具体实现是AnnotatedSubscriberFinder类。放到一个guava里定义的Multimap里。然后是把获取到的methodsInListener放到一个叫subscribersByType的 guava里定义的SetMultimap里 。

public Multimap, EventSubscriber> findAllSubscribers(Object listener) {

Multimap, EventSubscriber> methodsInListener = HashMultimap.create();

Class> clazz = listener.getClass();

for (Method method : getAnnotatedMethods(clazz)) {

Class>[] parameterTypes = method.getParameterTypes();

Class> eventType = parameterTypes[0];

EventSubscriber subscriber = makeSubscriber(listener, method);

methodsInListener.put(eventType, subscriber);

}

return methodsInListener;

}

1

2

3

4

5

6

7

8

9

10

11

publicMultimap,EventSubscriber>findAllSubscribers(Objectlistener){

Multimap,EventSubscriber>methodsInListener=HashMultimap.create();

Class>clazz=listener.getClass();

for(Methodmethod:getAnnotatedMethods(clazz)){

Class>[]parameterTypes=method.getParameterTypes();

Class>eventType=parameterTypes[0];

EventSubscribersubscriber=makeSubscriber(listener,method);

methodsInListener.put(eventType,subscriber);

}

returnmethodsInListener;

}

findAllSubscribers方法里,最重要的是methodsInListener,它的结构可以简单理解为一个map,其中key是eventType,在我前文写的例子中就是com.sww.eventbus.domain.MessageEvent,其中value是subscriber,就是例子中的com.sww.eventbus.listener.EventListener#onMessageEvent。

总之,一句话就是先通过标记找到所有已经注册进来的观察者,然后存放到容器里备用。

那unregister就是从容器删除它们,

unRegister (Object object) 解析

public void unregister(Object object) {

Multimap, EventSubscriber> methodsInListener = finder.findAllSubscribers(object);

for (Entry, Collection> entry :

methodsInListener.asMap().entrySet()) {

Class> eventType = entry.getKey();

Collection eventMethodsInListener = entry.getValue();

subscribersByTypeLock.writeLock().lock();

try {

Set currentSubscribers = subscribersByType.get(eventType);

if (!currentSubscribers.containsAll(eventMethodsInListener)) {

throw new IllegalArgumentException(

"missing event subscriber for an annotated method. Is " + object + " registered?");

}

currentSubscribers.removeAll(eventMethodsInListener);

} finally {

subscribersByTypeLock.writeLock().unlock();

}

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

publicvoidunregister(Objectobject){

Multimap,EventSubscriber>methodsInListener=finder.findAllSubscribers(object);

for(Entry,Collection>entry:

methodsInListener.asMap().entrySet()){

Class>eventType=entry.getKey();

CollectioneventMethodsInListener=entry.getValue();

subscribersByTypeLock.writeLock().lock();

try{

SetcurrentSubscribers=subscribersByType.get(eventType);

if(!currentSubscribers.containsAll(eventMethodsInListener)){

thrownewIllegalArgumentException(

"missing event subscriber for an annotated method. Is "+object+" registered?");

}

currentSubscribers.removeAll(eventMethodsInListener);

}finally{

subscribersByTypeLock.writeLock().unlock();

}

}

}

post( Object event)解析

有了观察者,下面就是发送事件了,阅读过前文会知道是通过eventBus.post(Object event)来发送事件消息。那咱们来看看这个post方法。

public void post(Object event) {

Set> dispatchTypes = flattenHierarchy(event.getClass());

boolean dispatched = false;

for (Class> eventType : dispatchTypes) {

subscribersByTypeLock.readLock().lock();

try {

Set wrappers = subscribersByType.get(eventType);

if (!wrappers.isEmpty()) {

dispatched = true;

for (EventSubscriber wrapper : wrappers) {

enqueueEvent(event, wrapper);

}

}

} finally {

subscribersByTypeLock.readLock().unlock();

}

}

if (!dispatched && !(event instanceof DeadEvent)) {

post(new DeadEvent(this, event));

}

dispatchQueuedEvents();

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

publicvoidpost(Objectevent){

Set>dispatchTypes=flattenHierarchy(event.getClass());

booleandispatched=false;

for(Class>eventType:dispatchTypes){

subscribersByTypeLock.readLock().lock();

try{

Setwrappers=subscribersByType.get(eventType);

if(!wrappers.isEmpty()){

dispatched=true;

for(EventSubscriberwrapper:wrappers){

enqueueEvent(event,wrapper);

}

}

}finally{

subscribersByTypeLock.readLock().unlock();

}

}

if(!dispatched&&!(eventinstanceofDeadEvent)){

post(newDeadEvent(this,event));

}

dispatchQueuedEvents();

}

该方法就是从之前的容器subscribersByType里获取到eventType对应的观察者,然后组装成EventWithSubscriber放到队列里。

void enqueueEvent(Object event, EventSubscriber subscriber) {

eventsToDispatch.get().offer(new EventWithSubscriber(event, subscriber));

}

1

2

3

voidenqueueEvent(Objectevent,EventSubscribersubscriber){

eventsToDispatch.get().offer(newEventWithSubscriber(event,subscriber));

}

然后就是最后的dispatchQueuedEvents(),经过一层层深入进去,可以发现wrapper.handleEvent(event),其中 handleEvent方法就是最终的关键了

public void handleEvent(Object event) throws InvocationTargetException {

checkNotNull(event);

try {

method.invoke(target, new Object[] { event });

} catch (IllegalArgumentException e) {

throw new Error("Method rejected target/argument: " + event, e);

} catch (IllegalAccessException e) {

throw new Error("Method became inaccessible: " + event, e);

} catch (InvocationTargetException e) {

if (e.getCause() instanceof Error) {

throw (Error) e.getCause();

}

throw e;

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

publicvoidhandleEvent(Objectevent)throwsInvocationTargetException{

checkNotNull(event);

try{

method.invoke(target,newObject[]{event});

}catch(IllegalArgumentExceptione){

thrownewError("Method rejected target/argument: "+event,e);

}catch(IllegalAccessExceptione){

thrownewError("Method became inaccessible: "+event,e);

}catch(InvocationTargetExceptione){

if(e.getCause()instanceofError){

throw(Error)e.getCause();

}

throwe;

}

}

就是通过Java的反射机制实现。

需要说明的是,如果没有订阅者注册到要发送的event事件上,并且该event不是DeadEvent,那么它将被包装成DeadEvent中并重新发布。也就是其中这三行代码索要做的

if (!dispatched && !(event instanceof DeadEvent)) {

post(new DeadEvent(this, event));

}

1

2

3

if(!dispatched&&!(eventinstanceofDeadEvent)){

post(newDeadEvent(this,event));

}

本文系本人原创,如要转载,请注明出处!

浏览量:

141

0

java eventbus 原理_EventBus原理解析相关推荐

  1. java eventbus 原理_本文为 Android 开源项目实现原理解析 EventBus 部分,从源码分析 EventBus 的实现原理...

    之前太忙导致 Android 开源项目实现原理解析 一度搁浅,目前一期进行中,我也完成了 EventBus 分析的初稿,大家可以稍微看看后面会继续润色下. PS:本文直接复制 Markdown,格式有 ...

  2. Java中高级核心知识全面解析——常用框架(SpringMVC-工作原理详解)

    一.先来看一下什么是 MVC 模式 MVC 是一种设计模式. MVC 的原理图如下: 二.SpringMVC 简单介绍 SpringMVC 框架是以请求为驱动,围绕 Servlet 设计,将请求发给控 ...

  3. java+cache使用方法_JVM代码缓存区CodeCache原理及用法解析

    一. CodeCache简介 从字面意思理解就是代码缓存区,它缓存的是JIT(Just in Time)编译器编译的代码,简言之codeCache是存放JIT生成的机器码(native code).当 ...

  4. java overload_Java方法重载Overload原理及使用解析

    这篇文章主要介绍了Java方法重载Overload原理及使用解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 为什么要用方法重载: 对于功能类似的 ...

  5. java中JVM的原理【转】

    一.java虚拟机的生命周期: Java虚拟机的生命周期 一个运行中的Java虚拟机有着一个清晰的任务:执行Java程序.程序开始执行时他才运行,程序结束时他就停止.你在同一台机器上运行三个程序,就会 ...

  6. Dubbo原理和源码解析之服务引用

    github新增仓库 "dubbo-read"(点此查看),集合所有<Dubbo原理和源码解析>系列文章,后续将继续补充该系列,同时将针对Dubbo所做的功能扩展也进行 ...

  7. 【java】Java 动态调试技术原理及实践

    1.概述 转载:Java 动态调试技术原理及实践 一.动态调试要解决的问题 断点调试是我们最常使用的调试手段,它可以获取到方法执行过程中的变量信息,并可以观察到方法的执行路径.但断点调试会在断点位置停 ...

  8. Spark SQL架构工作原理及流程解析

    Spark SQL架构工作原理及流程解析,spark sql从shark发展而来,Shark为了实现Hive兼容,在HQL方面重用了Hive中HQL的解析.逻辑执行计划翻译.执行计划优化等逻辑. Sp ...

  9. Java执行引擎工作原理:方法调用

    Java执行引擎工作原理:方法调用 方法调用如何实现 函数指针和指针函数 CallStub源码详解 Git链接(有HotSpot源码) 1 方法调用如何实现 计算机核心三大功能:方法调用.取指.运算 ...

最新文章

  1. mysql索引查询 with_mysql的select语句总结与索引使用
  2. web service 基础学习
  3. 人人都是产品经理读书笔记(四)
  4. redis之sorted sets类型及操作
  5. arraylist切割_jdk8 stream list分割 切割 分批次处理工具类
  6. Object.prototype的成员介绍
  7. go语言编程项目_一个项目需要多少种编程语言?
  8. 软件测试—软件测试基础知识—(五)软件测试模型
  9. Linux定时任务Crontab详解
  10. Speaker Recognition: Feature Extraction
  11. WDS和DHCP配置说明
  12. 英雄无敌王朝 服务器维护,《魔法门之英雄无敌:王朝》版本更新公告
  13. AI npc会做成为游戏制作人的梦吗?
  14. 华为员工离职心声:菊厂15年退休,感恩,让我实现了财务自由!
  15. 英语单词听力测试软件,英语单词发音软件
  16. el-table复选框全部勾选以及勾选回显
  17. 海螺环保上市破发:收盘市值178亿港元 由海螺创业分拆
  18. 科研伦理与学术规范(笔记)
  19. JAVA游戏 混乱大枪战
  20. elasticsearch下载太慢在国内, 我把包放到了云盘上,还有kibana,logstash.有需要自取,持续更新版本

热门文章

  1. 拉普拉斯------拉普拉斯变换
  2. Oracle ORA-01033: ORACLE initialization or shutdown in progress 错误解决办法Windows版(手贱强制重启电脑的后果)
  3. 分形维数学习个人笔记1
  4. win32 简易版扫雷
  5. 开发笔记 | Springboot整合多平台支付(微信/支付宝)
  6. html网页设计代码作业——家乡介绍-长治(8页) HTML+CSS+JavaScript 学生DW网页设计作业成品 html网页制作期末大作业成品_网页设计期末作业
  7. UBTC项目11月中旬研发披露
  8. 优雅炫酷的WordPress 导航主题 适合做小众化导航站 源码下载
  9. 成功集成个推后,点击推送直接跳入app指定页面
  10. day13 - 对指纹图片进行噪声消除