码迷,mamicode.com
首页 > 其他好文 > 详细

52.otto 源码解析

时间:2016-02-06 14:27:15      阅读:236      评论:0      收藏:0      [点我收藏+]

标签:

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();

注释源码

注释源码

52.otto 源码解析

标签:

原文地址:http://blog.csdn.net/qq_16430735/article/details/50640204

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!