文档章节

EventBus 源码学习笔记(三)

小灰灰Blog
 小灰灰Blog
发布于 2017/04/21 21:37
字数 585
阅读 30
收藏 1

EventBus 深入学习三之Guava小结

上一篇讲述了 EventBus 的整个执行流程, 本片则从细节处出发,探讨下设计的精妙

  1. 巧妙的利用缓存, 解决重复耗时的操作
  2. 异步化的操作
  3. 队列存储消息, 以及如何避免消息的重复消费
  4. 消费的先后顺序
  5. 截断
  6. 异常处理

1. 缓存

看代码时,可以看到很多地方都用到了缓存,如再注册时, 根据class获取所有带注解的方法; 推送消息时,根据事件类型,获取所有的超类集合

如注册时,一条完整的调用链

com.google.common.eventbus.SubscriberRegistry#register ->
com.google.common.eventbus.SubscriberRegistry#findAllSubscribers ->  com.google.common.eventbus.SubscriberRegistry#getAnnotatedMethods    ->
subscriberMethodsCache.getUnchecked(clazz) ->
com.google.common.eventbus.SubscriberRegistry#getAnnotatedMethodsNotCached

2. 根据类查询所有超类

TypeToken.of(concreteClass).getTypes().rawTypes());

// 我们自己的实现, 一直到返回null为止
clz.getSuperClass().getSuperClass();
// 获取接口
clz.getInterfaces()

3. 异步

异步推送处理Event和同步处理主要的区别点是使用的 Dispatcher不同, 同步是使用 PerThreadQueuedDispatcher , 异步是 LegacyAsyncDispatcher

异步的消息分发


/**
* Global event queue.
*/
private final ConcurrentLinkedQueue<EventWithSubscriber> queue =
   Queues.newConcurrentLinkedQueue();
   
@Override
    void dispatch(Object event, Iterator<Subscriber> subscribers) {
      checkNotNull(event);
      while (subscribers.hasNext()) {
        queue.add(new EventWithSubscriber(event, subscribers.next()));
      }

      EventWithSubscriber e;
      while ((e = queue.poll()) != null) {
        e.subscriber.dispatchEvent(e.event);
      }
    }

    private static final class EventWithSubscriber {
      private final Object event;
      private final Subscriber subscriber;

      private EventWithSubscriber(Object event, Subscriber subscriber) {
        this.event = event;
        this.subscriber = subscriber;
      }
    }
  }

同步的消息推送

/**
* Per-thread queue of events to dispatch.
*/
private final ThreadLocal<Queue<Event>> queue =
   new ThreadLocal<Queue<Event>>() {
     @Override
     protected Queue<Event> initialValue() {
       return Queues.newArrayDeque();
     }
   };
   
@Override
void dispatch(Object event, Iterator<Subscriber> subscribers) {
 checkNotNull(event);
 checkNotNull(subscribers);
 Queue<Event> queueForThread = queue.get();
 queueForThread.offer(new Event(event, subscribers));

 if (!dispatching.get()) {
   dispatching.set(true);
   try {
     Event nextEvent;
     while ((nextEvent = queueForThread.poll()) != null) {
       while (nextEvent.subscribers.hasNext()) {
         nextEvent.subscribers.next().dispatchEvent(nextEvent.event);
       }
     }
   } finally {
     dispatching.remove();
     queue.remove();
   }
 }
}

private static final class Event {
 private final Object event;
 private final Iterator<Subscriber> subscribers;

 private Event(Object event, Iterator<Subscriber> subscribers) {
   this.event = event;
   this.subscribers = subscribers;
 }
}
}

执行时, 在 AsyncEventBus 是在线程池中执行; 而 EventBus 则是直接执行, 实质上的执行器

public static Executor directExecutor() {
    return DirectExecutor.INSTANCE;
  }

  /** See {@link #directExecutor} for behavioral notes. */
  private enum DirectExecutor implements Executor {
    INSTANCE;
    @Override public void execute(Runnable command) {
      command.run();
    }
  }

4. 线程安全

5. 异常处理

  • 没有订阅者时, 抛一个 DeadEvent

  • 订阅者接收消息后的,执行异常时 (订阅者之间的隔离)

    • 看下具体的执行,比较清晰, 将异常抛给 EventBus的 ExceptionHandler统一处理
    final void dispatchEvent(final Object event) {
    executor.execute(new Runnable() {
      @Override
      public void run() {
        try {
          invokeSubscriberMethod(event);
        } catch (InvocationTargetException e) {
          bus.handleSubscriberException(e.getCause(), context(event));
        }
      }
    });
    }
    

6. 消费顺序 & 截断

Guava的EventBus不支持定义订阅者的顺序,更谈不上截断

© 著作权归作者所有

小灰灰Blog

小灰灰Blog

粉丝 208
博文 237
码字总数 423468
作品 0
武汉
程序员
私信 提问
基于 Kotlin Coroutine 实现的 EventBus

一. 背景 这段时间接手了一个比较紧急的项目,它是一个运行在某开发板上的 Android 项目。 该项目采用的架构比较老,例如 RxJava 还在使用 1.x 的版本。起初看到源码,我内心是拒绝的。(这大...

fengzhizi715
08/29
0
0
Guava库学习:学习Guava EventBus(一)EventBus

在软件开发过程中,对象信息的分享以及相互直接的协作是必须的,困难在于确保对象之间的沟通是有效完成的,而不是拥有成本高度耦合的组件。当对象对其他组件的责任有太多的细节时,它被认为是...

Realfighter
2014/12/29
4.3K
0
EventBus 3.0使用详解

01 前言 当我们进行项目开发的时候,往往是需要应用程序的各组件、组件与后台线程间进行通信,比如在子线程中进行请求数据,当数据请求完毕后通过Handler或者是广播通知UI,而两个Fragment之...

天王盖地虎626
05/09
45
0
Android EventBus 3.1.1最新源码分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SilenceOO/article/details/89506353 EventBus 3.1.1源码分析 前言 EventBus 是一款在 Android 开发中经常使用...

小黄花的故事
04/25
0
0
EventBus 消息的线程切换模型与实现原理

一. 序 EventBus 是一个基于观察者模式的事件订阅/发布框架,利用 EventBus 可以在不同模块之间,实现低耦合的消息通信。 EventBus 因为其使用简单且稳定,被广泛应用在一些生产项目中。 通常...

承香墨影
09/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

web前端开发初级

Web 页面制作基础 Web 的相关概念 WWW Website URL Web Standard Web Browser Web Server HTML 基础 标记语言 从 HTML 到 XHTML HTML 的基本结构 HTML 的相关基本定义 HTML 常用开发工具 HT...

达达前端小酒馆
19分钟前
2
0
PostgreSQL 11.3 locking

rudi
今天
5
0
Mybatis Plus sql注入器

一、继承AbstractMethod /** * @author beth * @data 2019-10-23 20:39 */public class DeleteAllMethod extends AbstractMethod { @Override public MappedStatement injectMap......

一个yuanbeth
今天
15
1
一次写shell脚本的经历记录——特殊字符惹的祸

本文首发于微信公众号“我的小碗汤”,扫码文末二维码即可关注,欢迎一起交流! redis在容器化的过程中,涉及到纵向扩pod实例cpu、内存以及redis实例的maxmemory值,statefulset管理的pod需要...

码农实战
今天
4
0
为什么阿里巴巴Java开发手册中不建议在循环体中使用+进行字符串拼接?

之前在阅读《阿里巴巴Java开发手册》时,发现有一条是关于循环体中字符串拼接的建议,具体内容如下: 那么我们首先来用例子来看看在循环体中用 + 或者用 StringBuilder 进行字符串拼接的效率...

武培轩
今天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部