EventBus3源码分析

引入

上一篇文章EventBus基本使用中讲述了EventBus使用的三个步骤

  • 第一步定义事件
public class MessageEvent {
 
    public final String message;
 
    public MessageEvent(String message) {
        this.message = message;
    }
}

  • 第二步准备观察者和订阅方法
@Override
public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}
 
@Override
public void onStop() {
    EventBus.getDefault().unregister(this);
    super.onStop();
}

// This method will be called when a MessageEvent is posted (in the UI thread for Toast)
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
    Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}
 
// This method will be called when a SomeOtherEvent is posted
@Subscribe
public void handleSomethingElse(SomeOtherEvent event) {
    doSomethingWith(event);
}

  • 第三步发送事件
EventBus.getDefault().post(new MessageEvent("Hello everyone!"));

如果你还不清楚EventBus的使用,请参考我的上一篇文章EventBus基本使用与进阶配置下面我们就从这个三个步骤,切入到源码中,分析EventBus的实现原理,这里笔者分析的是EventBus3.x版本的。

源码分析
  • EventBus.getDefault().register(Object subscriber)
// 注册主要做两件事 1.查找订阅者的所有订阅方法,2.将每个订阅方法与订阅者进行绑定(Subscription对象)
public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }
// 查找订阅者订阅方法的核心实现 通过反射/编译时注解生成的订阅信息
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
  			// 加了一层缓存,避免程序打开关闭,重复查找
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }
				// ignoreGeneratedIndex 这个变量控制是否通过注解处理器生成的订阅信息查找订阅方法,默认false
        if (ignoreGeneratedIndex) {
          	// 反射查找
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
          	// 从注解处理器生成的订阅信息Index中查找,找不到内部还是通过反射继续查找
            subscriberMethods = findUsingInfo(subscriberClass);
        }
  			// 没有找到订阅方法,抛出异常!!!
        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;
        }
    }

上面的代码分析可以看出查找订阅方法是通过 findUsingInfo/findUsingReflection ,findUsingInfo是EventBus3.0之后一个优化点,之前EventBus版本获取订阅者方法是通过反射获取,而反射是运行时解析注解信息消耗性能。而现在一些主流的框架例如(ButterKnife等)开始在编译时解析注解信息(采用注解处理器),这样大大提升了运行时性能。

// 在注解处理器生成的Index中进行订阅方法查找
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
  			// FindState,把它理解为一个临时对象,主要是用来保存每次查找的订阅信息的。
  			// 其次FindState,作者使用了一种享元的设计模式,优化可性能,因为register其实是频繁调用的
  			// 这样会创建大量的FindState临时对象,通过这种设计实现复用,每次用完回收到对象池中。有兴趣
  			// 可以自己深入源码研究研究,这里暂时不分析它了。
        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 {
              	// 这里可以看到,如果在注解处理器生成的Index订阅信息中没找到,继续反射查找
                findUsingReflectionInSingleClass(findState);
            }
          	// 移动至父类查找
            findState.moveToSuperclass();
        }
  			// 返回查找到的所有订阅方法,并且回收FindState对象
        return getMethodsAndRelease(findState);
    }
// 将订阅者的每个订阅方法与订阅者进行绑定,生成订阅关系Subscription
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class<?> eventType = subscriberMethod.eventType;
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
          	// 可能已经注册过了
            if (subscriptions.contains(newSubscription)) {
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "+ eventType);
            }
        }

        int size = subscriptions.size();
  			// 这个有个排序操作,相同事件,优先级高的订阅者排在优先级低的订阅者前面
  			// 注意这个在相同threadMode有效
        for (int i = 0; i <= size; i++) {
            if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
                subscriptions.add(i, newSubscription);
                break;
            }
        }
				// 保存订阅者的所有订阅事件Class
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);
				// 处理粘性事件,这里可以看到粘性事件的处理是regsiter中的。
  			// 粘性事件就是发送后,保存在内存中,之后订阅的时候,检测到订阅者有订阅粘性事件
  			// 则回调其订阅方法,订阅事件的处理下面分析
        if (subscriberMethod.sticky) {
            if (eventInheritance) {
                Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
                for (Map.Entry<Class<?>, Object> entry : entries) {
                    Class<?> candidateEventType = entry.getKey();
                    if (eventType.isAssignableFrom(candidateEventType)) {
                        Object stickyEvent = entry.getValue();
                        checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                    }
                }
            } else {
                Object stickyEvent = stickyEvents.get(eventType);
                checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }
    }
// 反射查找订阅方法
private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        try {
            methods = findState.clazz.getDeclaredMethods();
        } catch (Throwable th) {
            try {
                methods = findState.clazz.getMethods();
            } catch (LinkageError error) { 
                // ...some log info ignore
                throw new EventBusException(msg, error);
            }
            findState.skipSuperClasses = true;
        }
        for (Method method : methods) {
            int modifiers = method.getModifiers();
          	// public 修饰的,非abstract 非static
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                Class<?>[] parameterTypes = method.getParameterTypes();	
              	// 只有一个方法参数
                if (parameterTypes.length == 1) {
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                  	// 含有@Subscibe注解
                    if (subscribeAnnotation != null) {
                        Class<?> eventType = parameterTypes[0];
                      	// 检查 上面已经分析过了
                        if (findState.checkAdd(method, eventType)) {
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                    subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                        }
                    }
                } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
                    String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                    throw new EventBusException("@Subscribe method " + methodName +
                            "must have exactly 1 parameter but has " + parameterTypes.length);
                }
            } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
                String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                throw new EventBusException(methodName +
                        " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
            }
        }
    }

register流程就看完了,通过register流程,我们将订阅信息保存到了两个map中。

// 事件类型为key,订阅关系列表为value的map。Subscription=【subscriber,subscriberMethod;】
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
// 订阅者为key,订阅的事件类型列表为vlaue的map。
private final Map<Object, List<Class<?>>> typesBySubscriber;

// 订阅关系封装
final class Subscription {
  	// 订阅者
    final Object subscriber;
    // 订阅方法
    final SubscriberMethod subscriberMethod;
  	...
}
// 订阅方法封装
public class SubscriberMethod {
    final Method method;//方法
    final ThreadMode threadMode;//线程模式
    final Class<?> eventType;//事件类型
    final int priority;//优先级
    final boolean sticky;//是否是粘性事件
    ...
}  
  • EventBus.getDefault().unregister(Object subscriber)
// 解除注册,主要是移除所有该订阅者关联的订阅关系
public synchronized void unregister(Object subscriber) {
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            for (Class<?> eventType : subscribedTypes) {
              	// 移除subscriptionsByEventType中该订阅者相关的订阅关系
                unsubscribeByEventType(subscriber, eventType);
            }
          	// 移除typesBySubscriber中的订阅关系
            typesBySubscriber.remove(subscriber);
        } else {
            logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }

// 移除subscriptionsByEventType中的所有该订阅者关联的订阅关系
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
        List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions != null) {
            int size = subscriptions.size();
            for (int i = 0; i < size; i++) {
                Subscription subscription = subscriptions.get(i);
                if (subscription.subscriber == subscriber) {
                    subscription.active = false;
                    subscriptions.remove(i);
                    i--;
                    size--;
                }
            }
        }
    }
  • EventBus.getDefault().post(Object event)
// 发送事件
public void post(Object event) {
  			// 每个线程维护了一个发送状态,ThreadLocal,线程隔离,
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);

        if (!postingState.isPosting) {
            postingState.isMainThread = isMainThread();
            postingState.isPosting = true;
            if (postingState.canceled) {
                throw new EventBusException("Internal error. Abort state was not reset");
            }
            try {
              	// 遍历事件队列一个一个发送
                while (!eventQueue.isEmpty()) {
                  	// 发送单个事件
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
}

// 封装事件发送的一些状态信息
final static class PostingThreadState {
        final List<Object> eventQueue = new ArrayList<>();//事件队列
        boolean isPosting;//是否正在发送
        boolean isMainThread;//是否是主线程
        Subscription subscription;//订阅关系
        Object event;//事件
        boolean canceled;//是否取消了
}
// 发送事件
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
  			// 该属性控制是否查找事件的父类/父接口
  			// 意思是比如 AEvent extends BEvent implements CEvent
  			// 则最终会查找到三个事件 AEvent BEvent CEvent,然后遍历发送这三个事件
        if (eventInheritance) {
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
          	// 不向上查找,直接发送该事件
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
        if (!subscriptionFound) {
            if (logNoSubscriberMessages) {
                logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }
// 发送单个事件
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {	
          	// 找到该事件对应的订阅关系
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            for (Subscription subscription : subscriptions) {
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted;
                try {
                  	// 回调订阅方法
                    postToSubscription(subscription, event, postingState.isMainThread);
                    aborted = postingState.canceled;
                } finally {
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
              	// 如果事件被终止了,则结束剩余事件的发送
              	// POSTING模式可以在订阅方法中进行事件取消
                if (aborted) {
                    break;
                }
            }
            return true;
        }
        return false;
}
// 回调订阅方法,根据不同的线程模式,执行不同的调用策略,下面具体分析这几种线程模式实现
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {
            // POSTING模式
            case POSTING:
                invokeSubscriber(subscription, event);
                break;
            case MAIN:
            //  MAIN模式
                if (isMainThread) {
                    invokeSubscriber(subscription, event);
                } else {
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            // MAIN_ORDERED模式
            case MAIN_ORDERED:
                if (mainThreadPoster != null) {
                    mainThreadPoster.enqueue(subscription, event);
                } else {
                    invokeSubscriber(subscription, event);
                }
                break;
            // BACKGROUND模式
            case BACKGROUND:
                if (isMainThread) {
                    backgroundPoster.enqueue(subscription, event);
                } else {
                    invokeSubscriber(subscription, event);
                }
                break;
            // ASYNC模式
            case ASYNC:
                asyncPoster.enqueue(subscription, event);
                break;
            default:
                throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
        }
    }
// 兜兜转转 最终是反射调用了目标订阅方法
void invokeSubscriber(Subscription subscription, Object event) {
        try {
            subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
        } catch (InvocationTargetException e) {
            handleSubscriberException(subscription, event, e.getCause());
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Unexpected exception", e);
        }
    }
EventBus.getDefault().postSticky(Object event)
// 发送粘性事件
public void postSticky(Object event) {
        synchronized (stickyEvents) {
          	// 保存下来,这里是Map,相同类型的粘性事件会覆盖,订阅者将会收到最近最新的粘性事件
            stickyEvents.put(event.getClass(), event);
        }
        // 发送事件 post流程之前已经说过
        post(event);
}
三种Poster实现
  • HandlerPoster(事件需要在队列中排队执行)

    public class HandlerPoster extends Handler implements Poster {
    
      	// 存放执行的PostEvents 的事件队列
        private final PendingPostQueue queue;
      	// Post 事件在handleMessage 中执行的最大时间值
        private final int maxMillisInsideHandleMessage;
        private final EventBus eventBus;
      	// 标识Handler是否是运行的
        private boolean handlerActive;
    
        protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
            super(looper);
            this.eventBus = eventBus;
            this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
            queue = new PendingPostQueue();
        }
    
        public void enqueue(Subscription subscription, Object event) {
            PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
            synchronized (this) {
                queue.enqueue(pendingPost);
                // enqueue后,将这个poster运行起来,sendMessage,然后回到handleMessage中处理
              	// 之后每次事件存储在队列中,handleMessage则不断循环队列保存的事件进行处理调用
                if (!handlerActive) {
                    handlerActive = true;
                    if (!sendMessage(obtainMessage())) {
                        throw new EventBusException("Could not send handler message");
                    }
                }
            }
        }
    
        @Override
        public void handleMessage(Message msg) {
            boolean rescheduled = false;
            try {
                long started = SystemClock.uptimeMillis();
                while (true) {
                    PendingPost pendingPost = queue.poll();
                    if (pendingPost == null) {
                        synchronized (this) {
                            // Check again, this time in synchronized
                            pendingPost = queue.poll();
                            if (pendingPost == null) {
                                handlerActive = false;
                                return;
                            }
                        }
                    }
                  	// 回调订阅方法
                    eventBus.invokeSubscriber(pendingPost);
                    long timeInMethod = SystemClock.uptimeMillis() - started;
                    if (timeInMethod >= maxMillisInsideHandleMessage) {
                      	// 单个事件处理事件过长,重新sendMessage,剩下的事件在另一个message中处理
                        if (!sendMessage(obtainMessage())) {
                            throw new EventBusException("Could not send handler message");
                        }
                        rescheduled = true;
                        return;
                    }
                }
            } finally {
                handlerActive = rescheduled;
            }
        }
    }
    
  • BackgroundPoster(事件需要在线程池的单个线程中排队执行)

    final class BackgroundPoster implements Runnable, Poster {
    
      	// 事件队列
        private final PendingPostQueue queue;
        private final EventBus eventBus;
    
        private volatile boolean executorRunning;
    
        BackgroundPoster(EventBus eventBus) {
            this.eventBus = eventBus;
            queue = new PendingPostQueue();
        }
    
        public void enqueue(Subscription subscription, Object event) {
            PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
            synchronized (this) {
              	// enqueue之后,将这个poster运行起来
              	// 之后run方法中不断从队列中取出事件执行
                queue.enqueue(pendingPost);
                if (!executorRunning) {
                    executorRunning = true;
                  	// 这里是Executors.newCachedThreadPool(
                    eventBus.getExecutorService().execute(this);
                }
            }
        }
    
        @Override
        public void run() {
            try {
                try {
                    while (true) {
                        PendingPost pendingPost = queue.poll(1000);
                        if (pendingPost == null) {
                            synchronized (this) {
                                // Check again, this time in synchronized
                                pendingPost = queue.poll();
                                if (pendingPost == null) {
                                    executorRunning = false;
                                    return;
                                }
                            }
                        }
                      	// 回调订阅方法
                        eventBus.invokeSubscriber(pendingPost);
                    }
                } catch (InterruptedException e) {
                    eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
                }
            } finally {
                executorRunning = false;
            }
        }
    
    }
    
  • AsyncPoster(事件不需要排队,直接在线程池中执行)

    class AsyncPoster implements Runnable, Poster {
    
      	// 事件队列
        private final PendingPostQueue queue;
        private final EventBus eventBus;
    
        AsyncPoster(EventBus eventBus) {
            this.eventBus = eventBus;
            queue = new PendingPostQueue();
        }
    
      	// 事件一入队列,就放到线程池执行,不用排队,达到快速响应
        public void enqueue(Subscription subscription, Object event) {
            PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
            queue.enqueue(pendingPost);
            eventBus.getExecutorService().execute(this);
        }
    
        @Override
        public void run() {
            PendingPost pendingPost = queue.poll();
            if(pendingPost == null) {
                throw new IllegalStateException("No pending post available");
            }
          	// 回调订阅方法
            eventBus.invokeSubscriber(pendingPost);
        }
    
    }
    
总结
EventBus设计亮点
  • Builder设计模式,实现对象的自定义配置,灵活性很高

    EventBus参数的配置项实际上是通过EventBusBuildr配置的,通过我们调用getDefault()方式是通过一个默认的EventBusBuillder配置项获取EventBus实例。这样设计的好处便于拓展,通过EventBusBuilder你可以拓展自己的其他配置,而针对普通用户不需要拓展的通过一个默认配置项配置获取。这种设计方式可以应用到我们设计组件的时候,如果我们对外暴露的接口可以传入很多配置项的,这时候我们可以考虑这种设计,一般用户我们采用一个默认的配置。

  • 享元设计模式,比如FindState的对象池设计,PendingPost对象池设计,避免了大量临时对象的创建。实现了对象复用

    EventBus内部register/unregister,是会被频繁调用的,FindState是对register查找过程中生成的订阅信息的封装。那么每次会产生大量的临时对象,所以内部对象池的设计优化了内存使用,避免大量对象的创建。PendingPost也是同理,它是对post分发事件的封装,也是采用了对象池设计。

  • 策略模式,比如内部多种线程模式的支持,通过封装不同模式的策略,更加的解耦,灵活替换

    EventBus内部支持多种线程模式,通过策略模式设计,将不同的线程模式封装成Poster,更加的解耦,灵活替换。

  • 生产者消费者模式设计思想,比如内部支持线程模式的Poster的实现,通过Consumer-Producer实现事件的分发

    EventBus内部线程模式的实现Poster,内部通过单链表的形式封装了一个消息队列,事件在队列中进行传递消费。

  • ThreadLocal设计,每个发布线程维护自身的一个发布状态信息,使用ThreadLocal实现程隔离,相对于使用同步锁实现线程安全,速度更快。

  • EventBus3.x的优化,引入了注解处理器,编译时生成相关的订阅信息,替代了运行反射查找订阅方法对性能的消耗,优化了运行时性能。

思考感悟
  • 通过阅读EventBus源码,可以看出作者很多地方的精彩设计,很值得我们学习,在我们平时写代码的过程中,学会运用这种思想。这样自己才会提升
  • 任何优秀框架的设计都不是一遍两遍就能看明白的,要下功夫多看几遍,慢慢理解到作者的设计思路。这样才能便于我们理解整个源码
  • 举例阅读EventBus源码,我们首先抓住它的核心功能,是一个事件的订阅-发布系统,核心是观察者设计模式,如果让我们简单来设计这样一个组件通信,我们会怎么做,带着这种思路去看作者的思路,会更利于我们理解源码。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值