美文网首页
EventBus源码流程分析

EventBus源码流程分析

作者: 石器时代小古董 | 来源:发表于2018-07-27 16:22 被阅读0次

腾讯bulgy

一、EventBus的作用

它是一个事件的订阅-发布框架,用来解决组件件通信的问题

值得学习的是使用对象池减少对象的创建,将耗时业务放到编译时期执行的思路

二、EventBus的思路

事件发布前,先准备好订阅者的信息。在发布时候从已经准备好的订阅者信息中取出匹配的订阅者,发布事件。

三、查找订阅方法

查找订阅方法分为两种模式,
第一种是在register的时候通过反射查找所有的订阅方法
第二种是在编译时通过注解解析器,查找到所有的订阅方法

在Register通过反射查找
核心类

1.SubscriberMethodFinder:负责查找类中含有subscribe注解的所有方法
2.FindState:包装类的状态
3.METHOD_CACHE:缓存当前类对应的注解方法
4.findUsingInfo:通过已经准备好的订阅者索引集合查找订阅类
5.findUsingReflectionInSingleClass:解析类的注解,并添加到findstate中
6.SubscriberMethod 封装使用@Subscribe的方法

2.代码流程

1.通过SubscriberMethodFinder对象获取到当前类的所有添加了相应注解的方法
2.完成订阅

register方法
查找监听类中所有使用了subscribe注解的方法,并保存起来。

public void register(Object subscriber) {
        //获取当前监听类的类对象
        Class<?> subscriberClass = subscriber.getClass();
        //找到这个类下所有使用了subscribe标注的方法,并包装成SubscribeMethod集合
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                //将这些类
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

findSubscriberMethods---findUsingInfo---findUsingReflectionInSingleClass

1.同过SubscribeMethodFinder方法查找出类中所有使用了subscribe注解的方法

 /**
     * 监听类对象
     *
     * @param subscriberClass
     * @return
     */
    List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        //该类是否之前调用过,如果有从缓存中获取,如果没有 使用find方法查找
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }
        if (ignoreGeneratedIndex) {
           ....
        } else {
            subscriberMethods = findUsingInfo(subscriberClass);
        }
     .....
       return subscribeMethods
    }

1.创建FindState类维护这类的状态
2.将这些方法和方法的参数类型,线程类型记录下来,保存成SubscribeMethod对象
2.FindState保存所有这个类下使用了subscribe注解的方法


    private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        //准备一个FindState,这里运用了享元模式
        FindState findState = prepareFindState();
       //使用FindState记录下监听类
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            //第一次findstateinfo是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);
    }
 /**
     * FindState维护的是注册要监听的类
     * 这里要查找出这个类中所有使用了
     * subscribe注解的方法,保存起来
     * * @param findState  类监听方法对象
     */
    private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        try {
            // This is faster than getMethods, especially when subscribers are fat classes like Activities
            methods = findState.clazz.getDeclaredMethods();
        } catch (Throwable th) {
            // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
            methods = findState.clazz.getMethods();
            findState.skipSuperClasses = true;
        }
        //遍历查找类中的每一个方法,所有符合条件的类都加到findstate的subscribes集合中 记录下来
        for (Method method : methods) {
            //获取方法的修饰符类型
            int modifiers = method.getModifiers();
            //必须是publish 并且不能是静态的
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                //获取所有方法的参数类型
                Class<?>[] parameterTypes = method.getParameterTypes();
                //保证参数只有一个,根据参数类型的个数判断
                if (parameterTypes.length == 1) {
                    //判断方法是否含有subscribe注解
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                    if (subscribeAnnotation != null) {
                        //将第一个参数的类型取出来
                        Class<?> eventType = parameterTypes[0];
                        if (findState.checkAdd(method, eventType)) {
                            //获取subscribe注解里的threadmode值
                            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");
            }
        }
    }

subscribe方法的作用是将订阅了所有相同事件的方法通过一个Map(subscriptionsByEventType)维护起来,每个EventType都对应一个SubscribeMethod的集合,这样在发送的时候就可以查找到所有监听了这种事件的方法,将事件全部发送给他们。

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        //方法的参数类型
        Class<?> eventType = subscriberMethod.eventType;
        //将方法和注册监听的类关联起来
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        /**
         * 将监听方法根据参数类型保存起来,每个参数类型对应一个方法集合
         * paramsType--List<Subscription>
         * 相同的参数类型,放到一个集合中
         * 这样可以在发送事件的时候,将事件发送到所有监听了相同参数类型的方法中
         */
        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();
        for (int i = 0; i <= size; i++) {
            if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
                subscriptions.add(i, newSubscription);
                break;
            }
        }
        /**
         * 维护这个类下所有的订阅方法
         */
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);

        if (subscriberMethod.sticky) {
            if (eventInheritance) {
                // Existing sticky events of all subclasses of eventType have to be considered.
                // Note: Iterating over all events may be inefficient with lots of sticky events,
                // thus data structure should be changed to allow a more efficient lookup
                // (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
                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);
            }
        }
    }

二、Post方法

获取发送事件的类型,拿到通过register方法保存的监听改事件的所有方法(subscriptionsByEventType集合),并使用反射的方式执行所有维护的方法

1.PostingThreadState 记录当前线程的消息队列的状态,由ThreadLocal维护
2.postSingleEvent 发送消息

不同的线程都维护了一份PostingThreadState对象,负责维护消息的状态

 /**
     * 每一个线程都单独维护了一个PostingThreadState
     * 负责维护当前线程的事件以及事件分发的状态
     */
    private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
    };

   final static class PostingThreadState {
        final List<Object> eventQueue = new ArrayList<>();//消息嘟咧
        boolean isPosting;//是否发送
        boolean isMainThread;//是否是主线程
        Subscription subscription;//订阅的方法
        Object event;
        boolean canceled;
    }

Post方法发送事件

    /** Posts the given event to the event bus. */
    public void post(Object event) {
//获取当前线程消息队列的状态
        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;
            }
        }
    }
 /**
     * 发送事件
     * @param event 要发送的事件对象
     * @param postingState 当前线程的状态
     * @throws Error
     */
    private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        //获取要发送的事件的类型
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
     //evenInheritance默认是false
        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));
            }
        }
    }

postSingleEventForEventType
获取所有监听该事件的方法,并通过反射执行


    /**
     * 发送事件
     * @param event 事件对象
     * @param postingState  消息的线程状态
     * @param eventClass 事件的类型
     * @return 是否发送成功
     */
    private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            //根据发送事件的对象的类型,从通过register方法记录的保存的集合中subscriptionsByEventType找到所有监听该事件的集合
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
           //获取所有监听该事件对象的方法
            for (Subscription subscription : subscriptions) {
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted = false;
                try {
                    //使用反射执行
                    postToSubscription(subscription, event, postingState.isMainThread);
                    aborted = postingState.canceled;
                } finally {
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
                if (aborted) {
                    break;
                }
            }
            return true;
        }
        return false;
    }

    /**
     * 使用反射的方式发送数据
     * 如果不在对应的线程就使用handler发送到其它线程的looper队列中
     * @param subscription 监听类的包装
     * @param event 事件对象
     * @param isMainThread  是否在主线程
     */
    private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING:
                invokeSubscriber(subscription, event);
                break;
            case MAIN:
                if (isMainThread) {
                    invokeSubscriber(subscription, event);
                } else {
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case MAIN_ORDERED:
                if (mainThreadPoster != null) {
                    mainThreadPoster.enqueue(subscription, event);
                } else {
                    // temporary: technically not correct as poster not decoupled from subscriber
                    invokeSubscriber(subscription, event);
                }
                break;
            case BACKGROUND:
                if (isMainThread) {
                    backgroundPoster.enqueue(subscription, event);
                } else {
                    invokeSubscriber(subscription, event);
                }
                break;
            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提供了编译时生成索引信息的插件,使用方式腾讯bulgy
,它的原理是在编译时,插件执行注解解释器的代码,注解解释器会查找所有使用的subscribe注解的元素,检查他们是否符合标准,然后通过createInfoIndexFile生成订阅方法索引类。

/**
 * 设置支持的注解类型
 * 避免了只有在调用了register方法的时候才准备订阅者的信息
 * https://blog.csdn.net/natural_story/article/details/51444299
 * https://www.jianshu.com/p/899063e8452e Element
 */
@SupportedAnnotationTypes("org.greenrobot.eventbus.Subscribe")
@SupportedOptions(value = {"eventBusIndex", "verbose"})
public class EventBusAnnotationProcessor extends AbstractProcessor {
    public static final String OPTION_EVENT_BUS_INDEX = "eventBusIndex";
    public static final String OPTION_VERBOSE = "verbose";
   .....
   ......
    /** Found subscriber methods for a class (without superclasses). */
    /**
     * 找到所有订阅的方法
     */
    private final ListMap<TypeElement, ExecutableElement> methodsByClass = new ListMap<>();
    /**
     * 运行时注解
     * @param annotations
     * @param env
     * @return
     */
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
        //控制台输出的消息
        Messager messager = processingEnv.getMessager();
        try {
            String index = processingEnv.getOptions().get(OPTION_EVENT_BUS_INDEX);
          ......
          ....
            //找到所有符合条件的订阅方法
            collectSubscribers(annotations, env, messager);
           //校验方法的类是否符合要求
            checkForSubscribersToSkip(messager, indexPackage);

            if (!methodsByClass.isEmpty()) {
                /**
                 * 为使用了subscribe的类生成一个索引信息,包括方法名,方法参数类型,属于的类
                 * 包括他们的位置
                 */
                createInfoIndexFile(index);
            } else {
                messager.printMessage(Diagnostic.Kind.WARNING, "No @Subscribe annotations found");
            }
            writerRoundDone = true;
        } catch (RuntimeException e) {
            // IntelliJ does not handle exceptions nicely, so log and print a message
            e.printStackTrace();
            messager.printMessage(Diagnostic.Kind.ERROR, "Unexpected error in EventBusAnnotationProcessor: " + e);
        }
        return true;
    }

private void createInfoIndexFile(String index)方法会生成一个新的class
/** This class is generated by EventBus, do not edit. */
public class MyEventBusIndex implements SubscriberInfoIndex {
private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;
    static {
        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();
        // 每有一个订阅者类,就调用一次putIndex往索引中添加相关的信息
        putIndex(new SimpleSubscriberInfo(com.study.sangerzhong.studyapp.ui.MainActivity.class, true, new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("onEvent", com.study.sangerzhong.studyapp.ui.MainActivity.DriverEvent.class, ThreadMode.POSTING, 0, false), 
            // 类中每一个被Subscribe标识的方法都在这里添加进来
        })); 
    }
    // 下面的代码就是EventBusAnnotationProcessor中写死的了
    private static void putIndex(SubscriberInfo info) {
        SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
    }
 
    @Override
    public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {
        SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
        if (info != null) {
            return info;
        } else {
            return null;
        }
    }

将生成的索引信息类交给EventBus,这样在查找信息的时候会从索引集合中去匹配

EventBus.builder().addIndex(new MyEventBusIndex()).build()

    public EventBusBuilder addIndex(SubscriberInfoIndex index) {
        if (subscriberInfoIndexes == null) {
            subscriberInfoIndexes = new ArrayList<>();
        }
        subscriberInfoIndexes.add(index);
        return this;
    }

五、总结

将所有需要被调用的方法的状态记录下来(所属类,参数),在需要调用的时候,通过反射调用

相关文章

网友评论

      本文标题:EventBus源码流程分析

      本文链接:https://www.haomeiwen.com/subject/ldvbmftx.html