com.google.common.eventbus.Subscriber#dispatchEvent

  /**
* Dispatches {@code event} to this subscriber using the proper executor.
*/
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));
}
}
});
}

用例

本文主要按照如下例子展开:

//1. 新建bus对象,默认仅能在主线程上对消息进行调度
Bus bus = new Bus(); // maybe singleton //2. 新建类A(subscriber),answerAvailable()方法为事件回调,在主线程上运行
class A { public A() {
bus.register(this);
} // 可见性为public,仅有一个Event类型的参数
@Subscribe public void answerAvailable(AnswerAvailableEvent event) {
// process event
}
} //3. 往bus投递事件
bus.post(new AnswerAvailableEvent(42)); //4. 如果要A在注册时马上接收到一次回调,则可以新建类B(Producer),produceAnswer()
// 方法会在注册subscriber时,对每个订阅了AnswerAvailableEvent方法发送事件
class B { public B() {
bus.register(this);
} //可见性为public,不带任何参数
@Produce public AnswerAvailableEvent produceAnswer() {
return new AnswerAvailableEvent();
}
}

初始化

首先来看看Bus bus = new Bus()这一句,对应的源码如下所示:

public Bus() {
this(DEFAULT_IDENTIFIER);
} public Bus(String identifier) {
this(ThreadEnforcer.MAIN, identifier);
} public Bus(ThreadEnforcer enforcer, String identifier) {
this(enforcer, identifier, HandlerFinder.ANNOTATED);
} Bus(ThreadEnforcer enforcer, String identifier, HandlerFinder handlerFinder) {
this.enforcer = enforcer;
this.identifier = identifier;
this.handlerFinder = handlerFinder;
}

默认参数为enforcer = ThreadEnforcer.MAIN,identifier = DEFAULT_IDENTIFIER,handlerFinder = HandlerFinder.ANNOTATED。我们来看看这些参数是什么意思。

ThreadEnforcer

ThreadEnforcer是一个接口,enforce()方法用于检查当前线程是否为指定的线程类型:

public interface ThreadEnforcer {

    ThreadEnforcer ANY = new ThreadEnforcer() {
@Override
public void enforce(Bus bus) {
// Allow any thread.
}
}; ThreadEnforcer MAIN = new ThreadEnforcer() {
@Override
public void enforce(Bus bus) {
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException("Event bus " + bus +
" accessed from non-main thread " + Looper.myLooper());
}
}
}; void enforce(Bus bus);
}

不带参数的构造函数bus()使用默认的ThreadEnforcer.MAIN,表示enforce()方法必须在主线程上执行。

identifier

identifier仅为bus的名字,debug用。

handlerFinder

HandlerFinder用于在注册/反注册的时候查找Subscriber和Producer,后文会对其展开源码级别的解析。不带参数的构造函数bus()使用默认的HandlerFinder.ANNOTATED,表示使用注解来进行查找。

除上述以外,bus类还有两个成员变量handlersByType和producersByType:

private final ConcurrentMap<Class<?>, Set<EventHandler>> handlersByType =
new ConcurrentHashMap<Class<?>, Set<EventHandler>>(); private final ConcurrentMap<Class<?>, EventProducer> producersByType =
new ConcurrentHashMap<Class<?>, EventProducer>();

分别用于通过event的类型(class类型)来查找event handle和event producer。

注册/反注册事件

如下所示,要A成为订阅者订阅AnswerAvailableEvent,只需将其注册到bus,然后使用@Subscribe注解标记回调方法即可。回调方法要求可见性为public,有且仅有一个参数,类型为订阅的event。

class A {

    public A() {
bus.register(this);
} @Subscribe public void answerAvailable(AnswerAvailableEvent event) {
// process event
}
}

@Subscribe

首先看一下@Subscribe注解:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Subscribe {
}

RetentionPolicy.RUNTIME表示它是运行时的注解,ElementType.METHOD表示用于注解方法。

bus.register

再看一下register流程:

public void register(Object object) {
if (object == null) {
throw new NullPointerException("Object to register must not be null.");
}
//1. 检查当前线程是否符合ThreadEnforcer的设置
enforcer.enforce(this); //2. 默认情况下,通过注解在object上找出所有Producer
Map<Class<?>, EventProducer> foundProducers = handlerFinder.findAllProducers(object);
for (Class<?> type : foundProducers.keySet()) { //2-1. 查一下object上的producer注册的event是否已经被别人注册过。
final EventProducer producer = foundProducers.get(type);
EventProducer previousProducer = producersByType.putIfAbsent(type, producer);
//checking if the previous producer existed
if (previousProducer != null) {
throw new IllegalArgumentException("Producer method for type " + type + " found on type " + producer.target.getClass() + ", but already registered by type " + previousProducer.target.getClass() + ".");
}
//2-2. 如果没有注册过,那么找出对应event的handler,触发一次回调。
Set<EventHandler> handlers = handlersByType.get(type);
if (handlers != null && !handlers.isEmpty()) {
for (EventHandler handler : handlers) {
dispatchProducerResultToHandler(handler, producer);
}
}
} //3. 找出object上用@Subscribe注解了的方法
Map<Class<?>, Set<EventHandler>> foundHandlersMap = handlerFinder.findAllSubscribers(object);
for (Class<?> type : foundHandlersMap.keySet()) {
Set<EventHandler> handlers = handlersByType.get(type);
if (handlers == null) {
//3-1. 该event是第一次注册,那么新建一个CopyOnWriteArraySet用来保存handler和event的对应关系(EventHandler)
//concurrent put if absent
Set<EventHandler> handlersCreation = new CopyOnWriteArraySet<EventHandler>();
handlers = handlersByType.putIfAbsent(type, handlersCreation);
if (handlers == null) {
handlers = handlersCreation;
}
}
//3-2. 保存object中新增的event-handler对应关系。
final Set<EventHandler> foundHandlers = foundHandlersMap.get(type);
if (!handlers.addAll(foundHandlers)) {
throw new IllegalArgumentException("Object already registered.");
}
} //4. 检查object上的event是否存在对应的Producer,有则触发一次回调
for (Map.Entry<Class<?>, Set<EventHandler>> entry : foundHandlersMap.entrySet()) {
Class<?> type = entry.getKey();
EventProducer producer = producersByType.get(type);
if (producer != null && producer.isValid()) {
Set<EventHandler> foundHandlers = entry.getValue();
for (EventHandler foundHandler : foundHandlers) {
if (!producer.isValid()) {
break;
}
if (foundHandler.isValid()) {
dispatchProducerResultToHandler(foundHandler, producer);
}
}
}
}
}

总的来说register做了三件事情:触发新的Producer;注册新的event-handler关系;触发旧的Producer。另外有两点要注意一下:

  • 由于在一般使用场景下,发送/处理event远比注册/反注册操作频繁,所以在保证线程安全的情况下,使用CopyOnWriteArraySet作为保存event和handler的容器,可以大大提高效率。 
    CopyOnWrite容器在读的时候不会加锁,写的时候先复制一份,写完再替换原容器。如果容器正在写操作时发生了读操作(或者正在读的时候发生了写操作),读操作的对象为容器的快照(snapshot)。

  • 由于register方法没有加锁,所以在3-1中,尽管已经检查了handlers是否存在,但仍需使用putIfAbsent来保存handler。

EventProducer和EventHandler

注意到bus通过HandlerFinder来查找object上的producer和subscriber,接下来看一下HandlerFinder的实现:

interface HandlerFinder {
HandlerFinder ANNOTATED = new HandlerFinder() {
@Override
public Map<Class<?>, EventProducer> findAllProducers(
Object listener) {
return AnnotatedHandlerFinder.findAllProducers(listener);
} @Override
public Map<Class<?>, Set<EventHandler>> findAllSubscribers(
Object listener) {
return AnnotatedHandlerFinder.findAllSubscribers(listener);
}
}; Map<Class<?>, EventProducer> findAllProducers(Object listener);
Map<Class<?>, Set<EventHandler>> findAllSubscribers(Object listener);
}

其中findAllProducers方法返回某event type对应的EventProducer,findAllSubscribers返回某event type对应的EventHandler集合。先看一下EventProducer和EventHandler。

EventProducer是一个producer方法的包装类,源码如下:

class EventProducer {
final Object target; private final Method method; private final int hashCode; private boolean valid = true; EventProducer(Object target, Method method) {
if (target == null) {
throw new NullPointerException(
"EventProducer target cannot be null.");
} if (method == null) {
throw new NullPointerException(
"EventProducer method cannot be null.");
} this.target = target;
this.method = method;
method.setAccessible(true); // 提前计算hashcode,以防每次调用hash()时消耗资源
final int prime = 31;
hashCode = ((prime + method.hashCode()) * prime) + target.hashCode();
} public boolean isValid() {
return valid;
} // 应在object unregister时调用
public void invalidate() {
valid = false;
} public Object produceEvent() throws InvocationTargetException {
if (!valid) {
throw new IllegalStateException(toString() +
" has been invalidated and can no longer produce events.");
} try {
return method.invoke(target);
} catch (IllegalAccessException e) {
throw new AssertionError(e);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof Error) {
throw (Error) e.getCause();
} throw e;
}
}
}

其中produceEvent方法用于获得event。可以看出为什么Otto要求produce函数不能有参数。

与EventProducer类似,EventHandler是一个event handler方法(事件回调)的包装类,源码如下:

class EventHandler {

    private final Object target;

    private final Method method;

    private final int hashCode;

    private boolean valid = true;

    EventHandler(Object target, Method method) {
if (target == null) {
throw new NullPointerException(
"EventHandler target cannot be null.");
} if (method == null) {
throw new NullPointerException(
"EventHandler method cannot be null.");
} this.target = target;
this.method = method;
method.setAccessible(true); // Compute hash code eagerly since we know it will be used frequently and we cannot estimate the runtime of the
// target's hashCode call.
final int prime = 31;
hashCode = ((prime + method.hashCode()) * prime) + target.hashCode();
} public boolean isValid() {
return valid;
} public void invalidate() {
valid = false;
} public void handleEvent(Object event) throws InvocationTargetException {
if (!valid) {
throw new IllegalStateException(toString() +
" has been invalidated and can no longer handle events.");
} try {
method.invoke(target, event);
} catch (IllegalAccessException e) {
throw new AssertionError(e);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof Error) {
throw (Error) e.getCause();
} throw e;
}
}
}

其中handleEvent方法用于在object上调用handle方法(事件回调),传入event对象。可以看出为什么Otto要求event handler函数仅能有一个参数。

dispatchProducerResultToHandler

dispatchProducerResultToHandler方法用于将Producer产生的event分发给对应的handler。源码如下所示:

private void dispatchProducerResultToHandler(EventHandler handler, EventProducer producer) {
Object event = null;
try {
event = producer.produceEvent();
} catch(InvocationTargetException e) {
throwRuntimeException("Producer " + producer + " threw an exception.", e);
}
if (event == null) {
return;
}
dispatch(event, handler);
} protected void dispatch(Object event, EventHandler wrapper) {
try {
wrapper.handleEvent(event);
} catch(InvocationTargetException e) {
throwRuntimeException("Could not dispatch event: " + event.getClass() + " to handler " + wrapper, e);
}
}

逻辑比较简单,主要是使用了Producer的produceEvent()方法获得event对象后,调用EventHandler的handleEvent()方法。

bus.unregister

Bus类的unregister方法用于解除目标对象和bus之间的关联关系,包括对象上的producer方法,subscriber方法,源码如下所示:

public void unregister(Object object) {
if (object == null) {
throw new NullPointerException("Object to unregister must not be null.");
}
//1. 检查当前线程是否符合ThreadEnforcer的设置
enforcer.enforce(this); //2. 默认情况下,通过注解在object上找出所有Producer,将其从producersByType中删除并标记为invalidate
Map<Class<?>, EventProducer> producersInListener = handlerFinder.findAllProducers(object);
for (Map.Entry<Class<?>, EventProducer> entry : producersInListener.entrySet()) {
final Class<?> key = entry.getKey();
EventProducer producer = getProducerForEventType(key);
EventProducer value = entry.getValue(); if (value == null || !value.equals(producer)) {
throw new IllegalArgumentException(
"Missing event producer for an annotated method. Is " + object.getClass() + " registered?");
}
producersByType.remove(key).invalidate();
} //3. 默认情况下,找出object上用@Subscribe注解了的handler,将其从event集合中删除并标记为invalidate
Map<Class<?>, Set<EventHandler>> handlersInListener = handlerFinder.findAllSubscribers(object);
for (Map.Entry<Class<?>, Set<EventHandler>> entry : handlersInListener.entrySet()) {
Set<EventHandler> currentHandlers = getHandlersForEventType(entry.getKey());
Collection<EventHandler> eventMethodsInListener = entry.getValue(); if (currentHandlers == null || !currentHandlers.containsAll(eventMethodsInListener)) {
throw new IllegalArgumentException(
"Missing event handler for an annotated method. Is " + object.getClass() + " registered?");
} for (EventHandler handler : currentHandlers) {
if (eventMethodsInListener.contains(handler)) {
handler.invalidate();
}
}
currentHandlers.removeAll(eventMethodsInListener);
}
}

投递事件

一次简单的事件投递操作如下所示:

bus.post(new AnswerAvailableEvent(42));

我们来看一下post方法的源码实现:

public void post(Object event) {
if (event == null) {
throw new NullPointerException("Event to post must not be null.");
}
//1. 检查当前线程是否符合ThreadEnforcer的设置
enforcer.enforce(this); //2. 向上追溯event的所有父类
Set<Class<?>>dispatchTypes = flattenHierarchy(event.getClass()); //3. 当前event没有注册handler,则发送一个DeadEvent事件
boolean dispatched = false;
for (Class<?>eventType: dispatchTypes) {
Set<EventHandler> wrappers = getHandlersForEventType(eventType); if (wrappers != null && !wrappers.isEmpty()) {
dispatched = true;
for (EventHandler wrapper: wrappers) {
//3-1 将事件和handler放到分发队列里
enqueueEvent(event, wrapper);
}
}
} //4. 当前event没有注册handler,则发送一个DeadEvent事件
if (!dispatched && !(event instanceof DeadEvent)) {
post(new DeadEvent(this, event));
} //5. 通知队列进行分发操作
dispatchQueuedEvents();
}

注意几点:

  • 发送一个Event时,订阅了Event父类的Subscriber方法也会被调用。

  • 事件会被放到调用者所在线程的队列里依次分发。

下面分点进行详述。

flattenHierarchy

进行post操作时,首先会通过flattenHierarchy方法获得event的父类或者接口:

Set<Class<?>>flattenHierarchy(Class<?>concreteClass) {
Set<Class<?>>classes = flattenHierarchyCache.get(concreteClass);
if (classes == null) {
Set<Class<?>>classesCreation = getClassesFor(concreteClass);
classes = flattenHierarchyCache.putIfAbsent(concreteClass, classesCreation);
if (classes == null) {
classes = classesCreation;
}
}
return classes;
} private Set<Class<?>> getClassesFor(Class<?> concreteClass) {
List<Class<?>> parents = new LinkedList<Class<?>>();
Set<Class<?>> classes = new HashSet<Class<?>>(); parents.add(concreteClass); //深度优先遍历
while (!parents.isEmpty()) {
Class<?> clazz = parents.remove(0);
classes.add(clazz); Class<?> parent = clazz.getSuperclass();
if (parent != null) {
parents.add(parent);
}
}
return classes;
}

从上可知flattenHierarchy()通过getClassesFor()利用深度优先遍历导出了concreteClass的所有父类。

Dispatch Queue

通过post方法投递的event首先会放在当前线程所在的Dispatch Queue中,然后依次分发。Bus类有如下成员属性:

private final ThreadLocal<ConcurrentLinkedQueue<EventWithHandler>> eventsToDispatch =
new ThreadLocal<ConcurrentLinkedQueue<EventWithHandler>>() {
@Override protected ConcurrentLinkedQueue<EventWithHandler> initialValue() {
return new ConcurrentLinkedQueue<EventWithHandler>();
}
};

eventsToDispatch是一个ThreadLocal对象,通过initialValue()方法,eventsToDispatch每次在新的线程上调用的时候都会生成新的ConcurrentLinkedQueue实例。event是通过enqueueEvent(event, wrapper)方法放到queue中的,下面看看enqueueEvent()的实现:

protected void enqueueEvent(Object event, EventHandler handler) {
eventsToDispatch.get().offer(new EventWithHandler(event, handler));
}

offer()方法会会将EventWithHandler对象放到当前线程的queue的尾部。offer方法和add方法的区别在于,当无法插入(例如空间不够)的情况发生时会发挥false,热不是抛出异常。EventWithHandler类对event和handler的关系进行了简单的包装,实现如下:

static class EventWithHandler {
final Object event;
final EventHandler handler; public EventWithHandler(Object event, EventHandler handler) {
this.event = event;
this.handler = handler;
}
}

接下来看看dispatchQueuedEvents方法的实现:

protected void dispatchQueuedEvents() {
// don't dispatch if we're already dispatching, that would allow reentrancy and out-of-order events. Instead, leave
// the events to be dispatched after the in-progress dispatch is complete.
//1. 不能重复分发,否则会导致event的分发次序混乱
if (isDispatching.get()) {
return;
} isDispatching.set(true);
try {
while (true) {
//2. 依次取出EventWithHandler,并通过dispatch方法进行分发。
EventWithHandler eventWithHandler = eventsToDispatch.get().poll();
if (eventWithHandler == null) {
break;
} if (eventWithHandler.handler.isValid()) {
dispatch(eventWithHandler.event, eventWithHandler.handler);
}
}
} finally {
isDispatching.set(false);
}
}

值得注意的是,所有subscribe方法抛出的异常都会在这里捕获,捕获到异常以后event分发过程即停止,直到下一次在该线程上调用post为止。

结构图

综上,Otto的总体结构可用下图表示:

            +-------------------------+
|Bus(ThreadLocal) |
| +--------------+ |
| |EventProducers| |
| | +-------+ | register +-------+
| | |Produce| <----+-------+Produce|
| | +-------+ | | +-------+
| | +-------+ | |
| | |Produce| | |
| | +-------+ | |
| +--------------+ |
| | |
| event |
| | |
post(event)| +-------v--------+ |
+----------------> Dispatch Queue | |
| +-------+--------+ |
| | |
| event |
| | |
| +------v------+ |
| |EventHandlers| |
| | +---------+ | |
| | |Subscribe| | register +---------+
| | +---------+ <-----+-------+Subscribe|
| | +---------+ | | +---------+
| | |Subscribe| | |
| | +---------+ | |
| +-------------+ |
| |
+-------------------------+

https://segmentfault.com/a/1190000003982257

EventBus源码解析的更多相关文章

  1. EventBus源码解析 源码阅读记录

    EventBus源码阅读记录 repo地址: greenrobot/EventBus EventBus的构造 双重加锁的单例. static volatile EventBus defaultInst ...

  2. 【Android】EventBus 源码解析

    EventBus 源码解析 本文为 Android 开源项目实现原理解析 中 EventBus 部分项目地址:EventBus,分析的版本:ccc2771,Demo 地址:EventBus Demo分 ...

  3. Android EventBus源码解析 带你深入理解EventBus

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40920453,本文出自:[张鸿洋的博客] 上一篇带大家初步了解了EventBus ...

  4. Android EventBus源码解析

    项目地址 :https://github.com/greenrobot/EventBus 这个项目个人感觉就是为了解决回调事件过多的,比方说A函数在做完以后 要调用b类的c函数,那我们通常的做法就是 ...

  5. [EventBus源码解析] 订阅者处理消息的四种ThreadMode

    前言 在前面,我们探讨了如何在自己的代码中引入EventBus,进行基本的事件分发/监听:对注册观察者与事件发送的过程进行了浅析.从之前的学习中,我们了解到,EventBus一共有4种onEvent方 ...

  6. [EventBus源码解析] EventBus.post 方法详述

    前情概要 上一篇blog我们了解了EventBus中register/unregister的过程,对EventBus如何实现观察者模式有了基本的认识.今天我们来看一下它是如何分发一个特定事件的,即po ...

  7. [EventBus源码解析] EventBus.register 方法详述

    前情概要 在上一篇中,介绍了EventBus的基本使用方法,以及一部分进阶技巧.本篇及以后的几篇blog将会集中解析EventBus.java,看看作者是如何优雅地实现这个看似简单的事件分发/接收机制 ...

  8. 76.Android之EventBus源码解析

    转载:http://p.codekk.com/blogs/detail/54cfab086c4761e5001b2538 1. 功能介绍 1.1 EventBus EventBus 是一个 Andro ...

  9. [EventBus源码解析] 初探EventBus

    本期blog作为EventBus(以下简称EB)学习的始动篇,主要记载了EB的功能.优点.使用方法,内容基于github上的README.md与HOWTO.md. 何为EventBus EB实现了An ...

随机推荐

  1. FTP下文件夹权限的设置755,766,777,644代表什么意思

    一般情况下,为了网站更安全,我们需要给文件或文件夹设置权限,在采用FTP登录的方式下,经常会用到755,766,777,644等设置. 具体这些数字都代表什么意思呢? 这三个数字分别表示:不同用户或用 ...

  2. 像素转换问题-队列解决办法(或者dfs)

    在一定大小的像素图像中,将同色区域的颜色值替换为其他颜色值,从而产生新的图像,输入数据,图像大小,指定的像素点坐标,要替换成的颜色. 一开始出队操作写错了折腾半天,当队列中只有一个元素是出队后要将队首 ...

  3. 测试框架mochajs详解

    测试框架mochajs详解 章节目录 关于单元测试的想法 mocha单元测试框架简介 安装mocha 一个简单的例子 mocha支持的断言模块 同步代码测试 异步代码测试 promise代码测试 不建 ...

  4. python连接redis002

    例子001. 通过StrictRedis模式连接到redis.并调用get命令读取了一个string类型的值. #!/usr/bin/python #!coding:utf-8 import redi ...

  5. QP在STM32F10X上第一个应用

        两天没有写博客了,这两天主要还是在考虑软件的结构性问题,用不用QP?用不用ST库函数?看了ucos,freertos,tinyos以及Contiki,库函数的问题看了使用库的软件结构,直接操作 ...

  6. JVM 看不到某些异常的stacktrace问题(转)

    在java 1.5的release notes里面可以看到这样一句话: The compiler in the server VM now provides correct stack backtra ...

  7. 如何把Python2的代码转换为Python3的代码

    如何把Python2的代码转换为Python3的代码 注: 如果对于python2和python3不熟悉的,可以参考: [整理]总结Python2(Python 2.x版本)和Python3(Pyth ...

  8. POJ 3368 RMQ-ST

    一直感觉RMQ水,没自己写过,今天写了一道题,算是完全独立写的,这感觉好久没有了... 一直以来,都是为了亚洲赛学算法,出现了几个问题: 1.学的其实只是怎么用算法,对算法的正确性没有好好理解,或者说 ...

  9. C语言 EOF是什么?

    Linux中,在新的一行的开头,按下Ctrl-D,就代表EOF(如果在一行的中间按下Ctrl-D,则表示输出"标准输入"的缓存区,所以这时必须按两次Ctrl-D):Windows中 ...

  10. ExecuteReader(),ExecuteNonQuery(),ExecuteScalar(),ExecuteXmlReader()之间的区别

    本文来自:http://www.cnblogs.com/zhouxiaxue/archive/2006/05/12/398266.html http://www.cnblogs.com/yaoxc/a ...