看啥推荐读物
专栏名称: 龙衣袭
我就是我,做自己。 偶尔写写产品想法,和开发...
今天看啥  ›  专栏  ›  龙衣袭

EventBus 源码简单理解

龙衣袭  · 简书  ·  · 2018-12-21 22:41

今天这篇文章从源码去简单理解EventBus的实现。

从源码解读的主要模块有:

  • 入口
  • 注册、注销
  • 普通消息
  • 粘性消息

入口:

入口函数如下:

EventBus.getDefault()

进入源码我们可以看到EventBus是单例实现的,源码如下:

static volatile EventBus defaultInstance;
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
    if (defaultInstance == null) {
        synchronized (EventBus.class) {
            if (defaultInstance == null) {
                defaultInstance = new EventBus();
            }
        }
    }
    return defaultInstance;
}

这是一个双重检查单例模式(DCL), 还用到了关键字volatile

volatile 是什么?作用又是什么?
推荐查看这篇文章 Java并发编程:volatile关键字解析

在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞,volatile 关键字是一种比 sychronized 关键字更轻量级的同步机制。

synchronized 关键字

synchronized是什么?作用是什么?
推荐查看这篇文章 Java synchronized 详解

在构造函数中又调用了一个带参的构造函数,主要是用于用户自定义的配置,如果没配置就使用默认的配置信息,源码如下:

// 默认的builder
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

// 调用下方的构造函数
public EventBus() {
    this(DEFAULT_BUILDER);
}

// 初始化操作
EventBus(EventBusBuilder builder) {
    logger = builder.getLogger();
    subscriptionsByEventType = new HashMap<>();
    typesBySubscriber = new HashMap<>();
    stickyEvents = new ConcurrentHashMap<>();
    mainThreadSupport = builder.getMainThreadSupport();
    mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
    backgroundPoster = new BackgroundPoster(this);
    asyncPoster = new AsyncPoster(this);
    indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
    subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
            builder.strictMethodVerification, builder.ignoreGeneratedIndex);
    logSubscriberExceptions = builder.logSubscriberExceptions;
    logNoSubscriberMessages = builder.logNoSubscriberMessages;
    sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
    sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
    throwSubscriberException = builder.throwSubscriberException;
    eventInheritance = builder.eventInheritance;
    executorService = builder.executorService;
}

总结:使用单例双重检查锁模式。使用 synchronizedvolatila关键字是为了降低EventBus对象在并发操作时可能出现的原子性问题、可见性问题、有序性问题

register 操作

注册观察者

/**
 * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
 * are no longer interested in receiving events.
 * <p/>
 * Subscribers have event handling methods that must be annotated by {@link Subscribe}.
 * The {@link Subscribe} annotation also allows configuration like {@link
 * ThreadMode} and priority.
 */
public void register(Object subscriber) {
    Class<?> subscriberClass = subscriber.getClass();
    // 用 subscriberMethodFinder 提供的方法,找到在 subscriber 这个类里面订阅的内容。
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized (this) {
        // 为什么加锁?保证代码块的同步性,加锁会安全,但是性能会慢一些
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod);
        }
    }
}

findSubscriberMethods中找到订阅的集合, findSubscriberMethods方法的实现如下:

/**
* 键值对:键是类对象,值是List<SubscriberMethod> 集合对象。SubscriberMethod 是 每个订阅者与回调方法的关系对象,里面封装了包括优先级,是否接收黏性事件和所在线程等信息。
*/
private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
    // 在缓存中查找 SubscriberMethod  集合
    List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
    if (subscriberMethods != null) {
        return subscriberMethods;
    }
    //ignoreGeneratedIndex 属性表示是否忽略注解器生成的 MyEventBusIndex,ignoreGeneratedIndex 默认为false
    if (ignoreGeneratedIndex) {
        // 通过反射查找
        subscriberMethods = findUsingReflection(subscriberClass);
    } else {
        // 查找
        subscriberMethods = findUsingInfo(subscriberClass);
    }
    //在获得subscriberMethods以后,如果订阅者中不存在@Subscribe注解并且为public的订阅方法,则会抛出异常。
    if (subscriberMethods.isEmpty()) {
        throw new EventBusException("Subscriber " + subscriberClass
                + " and its super classes have no public methods with the @Subscribe annotation");
    } else {
        // 放入缓存
        METHOD_CACHE.put(subscriberClass, subscriberMethods);
        return subscriberMethods;
    }
}

ignoreGeneratedIndex 默认为``false`,源码如下:

/** Forces the use of reflection even if there's a generated index (default: false). */
public EventBusBuilder ignoreGeneratedIndex(boolean ignoreGeneratedIndex) {
    this.ignoreGeneratedIndex = ignoreGeneratedIndex;
    return this;
}

所以先查看这个findUsingInfo方法的实现

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
    FindState findState = prepareFindState();
    findState.initForSubscriber(subscriberClass);
    while (findState.clazz != null) {
        findState.subscriberInfo = getSubscriberInfo(findState);
        if (findState.subscriberInfo != null) {
            SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
            for (SubscriberMethod subscriberMethod : array) {
                if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                    findState.subscriberMethods.add(subscriberMethod);
                }
            }
        } else {
            findUsingReflectionInSingleClass(findState);
        }
        findState.moveToSuperclass();
    }
    return getMethodsAndRelease(findState);
}

明天补上。。。。。
总结:

注销

发消息

粘性消息




原文地址:访问原文地址
快照地址: 访问文章快照