52.otto 源码解析

otto 源码解析

Otto的源码非常简单,一共就九个类。


项目结构

  • AnnotatedHandlerFinder ( 查找并缓存所有注解方法 )
  • Bus ( otto核心业务类,包括注册、反注册、发送事件等等 )
  • DeadEvent ( 内置事件,没有订阅者,不能被传递 )
  • EventHandler ( 封装@Subscribe方法及其所在类 )
  • EventProducer ( 封装@Produce方法及其所在类 )
  • HandlerFinder ( 调用AnnotatedHandlerFinder的方法拿到注解方法,封装成EventHandler和EventProducer的集合 )
  • Produce ( @Produce )
  • Subscribe ( @Subscribe )
  • ThreadEnforcer ( 用于切换线程 )

register 实现

处理 @Produce 逻辑

  • 1.通过 AnnotatedHandlerFinder 找到 @Produce 方法
  • 2.然后 HandlerFinder 经由找回来的封装成Map<Class<?>, EventProducer>集合
  • 3.遍历Map<Class<?>, EventProducer>集合,逐个拿到该类对应的全部缓存的EventHandler
  • 4.这样就凑齐了@Subscribe@Produce 方法
  • 5.调用dispatchProducerResultToHandler处理:所谓的 提供 @Produce 被自身 @Subscribe 消费的流程
/**
 * 通过HandlerFinder找到所有
 * object里所有 @Produce 方法
 * 找回来的封装成EventProducer
 * 并且最后返回Map<Class<?>, EventProducer>
 */
Map<Class<?>, EventProducer> foundProducers = handlerFinder.findAllProducers(object);
for (Class<?> type : foundProducers.keySet()) {

    /**
     * 逐个拿到EventProducer
     */
    final EventProducer producer = foundProducers.get(type);
    /**
     * ConcurrentMap putIfAbsent 安全的put
     * 防止并发
     * 查看缓存 ConcurrentMap<Class<?>, EventProducer> 有木有
     */
    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() + ".");
    }

    /**
     * 逐个拿到全部缓存EventHandler ( @Subscribe方法封装类 )
     */
    Set<EventHandler> handlers = handlersByType.get(type);
    if (handlers != null && !handlers.isEmpty()) {
        for (EventHandler handler : handlers) {
            /**
             * 逐个去调用@Subscribe 和 @Produce 方法
             */
            dispatchProducerResultToHandler(handler, producer);
        }
    }
}

处理 @SubScribe 逻辑

  • 1.通过 AnnotatedHandlerFinder 找到 @Subscribe 方法
  • 2.然后 HandlerFinder 经由找回来的封装成Map<Class<?>, Set<EventHandler>>集合
  • 3.先遍历Map<Class<?>, Set<EventHandler>>集合,拿到Set<EventHandler>刷新缓存
  • 4.再次循环Map<Class<?>, Set<EventHandler>>集合,查找对应类的Set<EventProducer>缓存。
  • 6.调用dispatchProducerResultToHandler处理,再一次完成:所谓的 提供 @Produce 被自身 @Subscribe 消费的流程
/**
 * 通过HandlerFinder找到所有
 * object里所有 @SubScribe 方法
 * 找回来的封装成EventHandler
 * Map<Class<?>, Set<EventHandler>>
 */
Map<Class<?>, Set<EventHandler>> foundHandlersMap = handlerFinder.findAllSubscribers(object);

/**
 * 逐个拿到EventHandler
 */
for (Class<?> type : foundHandlersMap.keySet()) {

    /**
     * 拿到缓存 EventHandler 集合
     */
    Set<EventHandler> handlers = handlersByType.get(type);
    if (handlers == null) {
        //concurrent put if absent
        Set<EventHandler> handlersCreation = new CopyOnWriteArraySet<EventHandler>();

        /**
         * 往缓存 EventHandler Map 里放入一份 type 对应的 EventHandle 集合
         */
        handlers = handlersByType.putIfAbsent(type, handlersCreation);
        if (handlers == null) {
            handlers = handlersCreation;
        }
    }
    final Set<EventHandler> foundHandlers = foundHandlersMap.get(type);
    if (!handlers.addAll(foundHandlers)) {
        throw new IllegalArgumentException("Object already registered.");
    }
}

/**
 * 遍历所有找到 EventHandler ( @Subscribe方法 )
 */
for (Map.Entry<Class<?>, Set<EventHandler>> entry : foundHandlersMap.entrySet()) {
    Class<?> type = entry.getKey();
    /**
     * 再拿一次 EventProducer 缓存
     * 如果object 里 存在 @Producer 方法
     * 才循环 EventHandler 的逻辑里去 调用
     * dispatchProducerResultToHandler方法
     */
    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);
            }
        }
    }
}

unregister 实现

  • 1.通过 AnnotatedHandlerFinder 找到 @Produce 方法
  • 2.然后 HandlerFinder 经由找回来的封装成Map<Class<?>, EventProducer>集合
  • 3.遍历Map<Class<?>, EventProducer>集合,逐个拿到EventProducer,并去查找是否存在该EventProducer缓存。
  • 4.存在缓存 ,从 EventProducer 缓存Map里移除,调用 EventProducer.invalidate()方法
/**
 * 通过HandlerFinder找到所有
 * object里所有 @Produce 方法
 * 找回来的封装成EventProducer
 * 并且最后返回Map<Class<?>, EventProducer>
 */
Map<Class<?>, EventProducer> producersInListener = handlerFinder.findAllProducers(object);
for (Map.Entry<Class<?>, EventProducer> entry : producersInListener.entrySet()) {
    final Class<?> key = entry.getKey();

    /**
     * 拿到对应的 EventProducer
     * 这里只拿一个 又表明了:
     * 一个 object 只存在 一个 EventProducer
     * producer 表示 已缓存的 该 object 的 所有 EventProducer
     * value 表示 通过Finder 找到的 所有 EventHandler
     */
    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?");
    }
    /**
     * 从 EventProducer 缓存Map里移除
     * 并调用 EventProducer.invalidate()方法
     * 设置该 EventProducer 不合法
     */
    producersByType.remove(key).invalidate();
}
  • 1.通过 AnnotatedHandlerFinder 找到 @Subscribe 方法
  • 2.然后 HandlerFinder 经由找回来的封装成Map<Class<?>, Set<EventHandler>>集合
  • 3.遍历Map<Class<?>, Set<EventHandler>>集合,拿到Set<EventHandler>集合,查看是否存在该缓存。
  • 4.存在缓存,继续遍历Set<EventHandler>集合,拿到EventHandler。
  • 5.如果 缓存的 EventHandler,又存在 Finder 先查的 EventHandler 之中,标记为不合法。
  • 6.删除该Set<EventHandler>集合的缓存

post 实现

先讲讲,这里有个方法,作用是 一个类的所有父类,包括自己,存储为一个 Set 集合

也是otto一个工具方法

getClassesFor

/**
 * 寻找一个类所有父类 包括自己 存为一个 Set 集合
 *
 * @param concreteClass concreteClass
 * @return Set<Class<?>>
 */
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;
}

接着说说 post 的实现具体流程:

  • 1.通过flattenHierarchy方法去处理改事件的家谱集合( 自己+父类的集合 ),返回一个Set<Class<?>>集合
  • 1.1.flattenHierarchy方法先看看flattenHierarchyCache缓存里是否存在该事件的家谱集合( 自己+父类的集合 )
  • 1.2.flattenHierarchyCache里存在该事件的缓存,直接返回
  • 1.3.flattenHierarchyCache里不存在该事件的缓存,则调用getClassesFor去收集该类的家谱集合( 自己+父类的集合 ),缓存一份到flattenHierarchyCache中,再返回
  • 2.遍历这个Set<Class<?>>集合( 家谱集合 ),然后拿到该监听类的缓存Set<EventHandler>集合,再遍历Set<EventHandler>集合,进入的到enqueueEvent里用 事件 + EventHandler 包装成 EventWithHandler对象,并且执行入队逻辑
  • 3.判断是否该事件没有订阅者,并不是DeadEvent事件。符合,就给发一个DeadEvent事件
  • 4.最后会溜达到dispatchQueuedEvents里处理事件队列
/**
 * 拿到 该事件 + 该事件所有父类 的Set集合
 */
Set<Class<?>> dispatchTypes = flattenHierarchy(event.getClass());

boolean dispatched = false;
/**
 * 遍历该事件 + 该事件所有父类 的Set集合
 */
for (Class<?> eventType : dispatchTypes) {

    /**
     * 拿到 该 object 所有缓存 EventHandler
     */
    Set<EventHandler> wrappers = getHandlersForEventType(eventType);

    /**
     * 开始进入 遍历缓存的 EventHandler
     * 并处理事件
     * 进入 enqueueEvent 逻辑
     */
    if (wrappers != null && !wrappers.isEmpty()) {
        dispatched = true;
        for (EventHandler wrapper : wrappers) {
            /**
             * 事件 + EventHandler 包装成 EventWithHandler
             * 入队
             */
            enqueueEvent(event, wrapper);
        }
    }
}

/**
 * 根据上面的循环可知道
 * 如果 object 存在 一个 EventHandler
 * 并且post的 事件不是 DeadEvent
 * 就会执行一次 post(new DeadEvent(this, event))
 */
if (!dispatched && !(event instanceof DeadEvent)) {
    post(new DeadEvent(this, event));
}

dispatchQueuedEvents();

注释源码

注释源码

时间: 2024-10-12 07:41:34

52.otto 源码解析的相关文章

[slf4j+log] 源码解析

slf4j: The Simple Logging Facade for java即 java简单的日志门面.统一定义了一系列的日志接口,使用户可以使用统一的接口来记录日志.logback,log4j等框架都实现了这些接口,启动时动态地决定真正的日志框架.本文以slf4j+logback的源码来讲解整个绑定和打印日志的流程. 手动阅读目录如下: 绑定日志框架 解析配置文件获取LoggerFactory:对于logback而言就是LoggerContext 获取Logger:在LoggerActi

String源码解析(一)

本篇文章内的方法介绍,在方法的上面的注释讲解的很清楚,这里只阐述一些要点. Java中的String类的定义如下: 1 public final class String 2 implements java.io.Serializable, Comparable<String>, CharSequence { ...} 可以看到,String是final的,而且继承了Serializable.Comparable和CharSequence接口. 正是因为这个特性,字符串对象可以被共享,例如下面

Java 集合系列05之 LinkedList详细介绍(源码解析)和使用示例

概要  前面,我们已经学习了ArrayList,并了解了fail-fast机制.这一章我们接着学习List的实现类——LinkedList.和学习ArrayList一样,接下来呢,我们先对LinkedList有个整体认识,然后再学习它的源码:最后再通过实例来学会使用LinkedList.内容包括:第1部分 LinkedList介绍第2部分 LinkedList数据结构第3部分 LinkedList源码解析(基于JDK1.6.0_45)第4部分 LinkedList遍历方式第5部分 LinkedL

Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例

java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例 概要  和学习ArrayList一样,接下来呢,我们先对LinkedList有个整体认识,然后再学习它的源码:最后再通过实例来学会使用LinkedList.内容包括:第1部分 LinkedList介绍第2部分 LinkedList数

Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例

java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例 概要 上一章,我们学习了Collection的架构.这一章开始,我们对Collection的具体实现类进行讲解:首先,讲解List,而List中ArrayList又最为常用.因此,本章我们讲解ArrayList.先对ArrayLis

消息中间件 RocketMQ源码解析:事务消息

关注微信公众号:[芋艿的后端小屋]有福利: RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表 RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址 您对于源码的疑问每条留言都将得到认真回复.甚至不知道如何读源码也可以请教噢. 新的源码解析文章实时收到通知.每周更新一篇左右. 1. 概述 2. 事务消息发送 2.1 Producer 发送事务消息 2.2 Broker 处理结束事务请求 2.3 Broker 生成

给jdk写注释系列之jdk1.6容器(2)-LinkedList源码解析

LinkedList是基于链表结构的一种List,在分析LinkedList源码前有必要对链表结构进行说明. 1.链表的概念 链表是由一系列非连续的节点组成的存储结构,简单分下类的话,链表又分为单向链表和双向链表,而单向/双向链表又可以分为循环链表和非循环链表,下面简单就这四种链表进行图解说明.           1.1.单向链表 单向链表就是通过每个结点的指针指向下一个结点从而链接起来的结构,最后一个节点的next指向null.      1. 2.单向循环链表           单向循环

【转】Java HashMap 源码解析(好文章)

- .fluid-width-video-wrapper { width: 100%; position: relative; padding: 0; } .fluid-width-video-wrapper iframe, .fluid-width-video-wrapper object, .fluid-width-video-wrapper embed { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } [

Java集合---LinkedList源码解析

一.源码解析1. LinkedList类定义2.LinkedList数据结构原理3.私有属性4.构造方法5.元素添加add()及原理6.删除数据remove()7.数据获取get()8.数据复制clone()与toArray()9.遍历数据:Iterator()二.ListItr 一.源码解析 1. LinkedList类定义. public class LinkedList<E> extends AbstractSequentialList<E> implements List&