EventBus 开源库学习(三)

这篇具有很好参考价值的文章主要介绍了EventBus 开源库学习(三)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

源码细节阅读

上一节根据EventBus的使用流程把实现源码大体梳理了一遍,因为精力有限,所以看源码都是根据实现过程把基本流程看下,中间实现细节先忽略,否则越看越深不容易把握大体思路,这节把一些细节的部分再看看。

注解函数查找源码逻辑

#EventBus   
 public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

在进行注册的时候,我们使用subscriberMethodFinder对象的findSubscriberMethods方法来查找到所有该类中以@Subscribe注解的函数(以下简称为注解函数)。让我们继续看下查找部分的逻辑。

    List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }

        if (ignoreGeneratedIndex) {
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
            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;
        }
    }

METHOD_CACHE是一个ConcurrentHashMap类型的常量,用来保存subscriberClass和对应SubscriberMethod的集合,以提高注册效率,防止重复查找。

如果METHOD_CACHE缓存中不存在,判断变量ignoreGeneratedIndex的值,该值是在EventBusBuilder中初始化的,表示是否忽略注解生成器,默认是false。然后会进入到findUsingInfo函数中进行查找(下面再看),最后将找到的subscriberMethods添加到METHOD_CACHE中。

    private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        ````
        return getMethodsAndRelease(findState);
    }

先看findUsingInfo前两行,出现一个FindState类,它是SubscriberMethodFinder的内部类,用来辅助查找订阅事件的方法。

    private FindState prepareFindState() {
        synchronized (FIND_STATE_POOL) {
            for (int i = 0; i < POOL_SIZE; i++) {
                FindState state = FIND_STATE_POOL[i];
                if (state != null) {
                    FIND_STATE_POOL[i] = null;
                    return state;
                }
            }
        }
        return new FindState();
    }


    static class FindState {
        ```
        void initForSubscriber(Class<?> subscriberClass) {
            this.subscriberClass = clazz = subscriberClass;
            skipSuperClasses = false;
            subscriberInfo = null;
        }
     }

prepareFindState()方法主要是返回一个FindState对象,先从FIND_STATE_POOL这个缓存池中获取一个现成的,如果没有就新建一个对象。获取对象后调用初始化方法,将subscriberClass赋值给clazz变量,subscriberInfo对象赋值为null

    private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            findState.subscriberInfo = getSubscriberInfo(findState);
            if (findState.subscriberInfo != null) {
                ```
            } else {
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }

再回到findUsingInfo,因为findState.clazz刚赋值过,所以不为空。再来看下getSubscriberInfo方法。

    private SubscriberInfo getSubscriberInfo(FindState findState) {
        if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
            SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
            if (findState.clazz == superclassInfo.getSubscriberClass()) {
                return superclassInfo;
            }
        }
        if (subscriberInfoIndexes != null) {
            for (SubscriberInfoIndex index : subscriberInfoIndexes) {
                SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
                if (info != null) {
                    return info;
                }
            }
        }
        return null;
    }

前面执行initForSubscriber的时候,subscriberInfo赋值为null,因此第一个if不成立。第二个判断是对象subscriberInfoIndexes,该变量也是在EventBusBuilder中初始化的,默认是null,因此该方法返回值null

    private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            findState.subscriberInfo = getSubscriberInfo(findState);
            if (findState.subscriberInfo != null) {
                ```
            } else {
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }

再回到findUsingInfo,由于getSubscriberInfo返回为null,逻辑会走到findUsingReflectionInSingleClass方法中,使用反射来获取所有方法(下面再看)。

获取当前类所有的注解方法后,findState.moveToSuperclass()表示修改findState.clazzsubscriberClass的父类Class,继续遍历父类中的注解方法。

private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC;

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
            ```
        }
        for (Method method : methods) {
            int modifiers = method.getModifiers();
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                Class<?>[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length == 1) {
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                    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");
            }
        }
    }

上面代码流程如下:

  • 通过方法getDeclaredMethods()获取该类中所有声明的方法列表;
  • 遍历方法列表,获取方法的修饰符,如果修饰符是public并且不是abstractstatic等进入下一步,MODIFIERS_IGNORE定义如第一行代码;
  • 获取方法的参数列表,如果参数的个数是1,并且使用了Subscribe注解,获取唯一的入参进行下一步;
  • 然后checkAdd()方法用来判断FindState的anyMethodByEventType map是否已经添加过以当前eventTypekey的键值对,没添加过则返回true(就是看看当前类中有没有多个事件相同的注解函数);
  • 通过注解对象subscribeAnnotation获取threadMode,然后新建SubscriberMethod添加到findState.subscriberMethods集合中。

分析完findUsingReflectionInSingleClass这个方法后,我们回到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) {
                ```
            } else {
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }

遍历当前类及其父类,通过findUsingReflectionInSingleClass方法找到所有注解方法后,通过getMethodsAndRelease返回所有相关方法。

    private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
        List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
        findState.recycle();
        synchronized (FIND_STATE_POOL) {
            for (int i = 0; i < POOL_SIZE; i++) {
                if (FIND_STATE_POOL[i] == null) {
                    FIND_STATE_POOL[i] = findState;
                    break;
                }
            }
        }
        return subscriberMethods;
    }

通过上面的解析知道,所有的SubscriberMethod都添加到findState.subscriberMethods集合中,这个方法就是把findState.subscriberMethods集合中的内容复制出来,然后释放findState中的资源,并把findState放到FIND_STATE_POOL缓存中,POOL_SIZE常量是4,这样下次查找的时候可以重复利用无需每次都新建对象。

以上为注解方法查找的过程。在上面分析的过程中出现了两个变量subscriberInfoIndexesignoreGeneratedIndex看样子都是关于索引的,分析的时候都是使用的EventBusBuilder中的默认值。看下subscriberInfoIndexes赋值的地方,看注释意思是:将EventBus注解处理器生成索引添加添加进来。所以注解处理器需要再了解下。

    /** Adds an index generated by EventBus' annotation preprocessor. */
    public EventBusBuilder addIndex(SubscriberInfoIndex index) {
        if (subscriberInfoIndexes == null) {
            subscriberInfoIndexes = new ArrayList<>();
        }
        subscriberInfoIndexes.add(index);
        return this;
    }

Subscriber Index注解处理器

通过上面分析可知,EventBus注册事件时,主要是在项目运行时通过反射来查找注解方法信息,如果项目中有大量的注解方法,必然会对项目运行时的性能产生影响。

除了在项目运行时通过反射查找注解方法信息,EventBus 还提供了在项目编译时通过注解处理器查找注解方法信息的方式,生成一个辅助的索引类来保存这些信息,这个索引类就是Subscriber Index。

1、Subscriber Index使用方式
首先要在 appbuild.gradle中加入如下配置:

android {
    defaultConfig {
        javaCompileOptions {
            annotationProcessorOptions {
                // 指定辅助索引类的名称和包名,注意,这个类时自动生成的,不需要我们写
                arguments = [ eventBusIndex : 'com.jane.demo.MyEventBusIndex' ]
            }
        }
    }
}
dependencies {
    compile 'org.greenrobot:eventbus:3.3.1'
    // 引入注解处理器
    annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.3.1'
}

在项目的Application中添加如下配置,以生成一个默认的 EventBus 单例:

EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();

此时重新编译下项目,会生成一个MyEventBusIndex类(不同的gradle版本生成的位置可能不一样)。
EventBus 开源库学习(三),开源库学习,开源,学习,windows

生成的MyEventBusIndex代码如下:

public class MyEventBusIndex implements SubscriberInfoIndex {
    private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;

    static {
        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();

        putIndex(new SimpleSubscriberInfo(EventBusService.class, true, new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("onMsgEventReceived", String.class),
            new SubscriberMethodInfo("onMsgEventReceived", MsgEvent.class),
            new SubscriberMethodInfo("onMsgEventReceived", org.greenrobot.eventbus.NoSubscriberEvent.class),
        }));

        putIndex(new SimpleSubscriberInfo(EventBusActivity.class, true, new SubscriberMethodInfo[] {
             new SubscriberMethodInfo("onMsgEventReceived", Event.class),
        }));
    }

    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;
        }
    }
}

代码中SUBSCRIBER_INDEX是一个HashMap,保存了当前注册类的Class类型和其中注解方法的信息。

2、Subscriber Index源码

EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();

使用的时候,获取EventBusBuilder对象,然后调用addIndex方法,把生成的MyEventBusIndex加入进去。

    /** Adds an index generated by EventBus' annotation preprocessor. */
    public EventBusBuilder addIndex(SubscriberInfoIndex index) {
        if (subscriberInfoIndexes == null) {
            subscriberInfoIndexes = new ArrayList<>();
        }
        subscriberInfoIndexes.add(index);
        return this;
    }

上面的方法是不是比较眼熟,就是上面代码分析的时候出现的变量subscriberInfoIndexes赋值函数。这样,运行的时候就把之前编译好的索引类的实例保存在subscriberInfoIndexes集合中。然后调用installDefaultEventBus方法创建EventBus实例。

    /**
     * Installs the default EventBus returned by {@link EventBus#getDefault()} using this builders' values. Must be
     * done only once before the first usage of the default EventBus.
     *
     * @throws EventBusException if there's already a default EventBus instance in place
     */
    public EventBus installDefaultEventBus() {
        synchronized (EventBus.class) {
            if (EventBus.defaultInstance != null) {
                throw new EventBusException("Default instance already exists." +
                        " It may be only set once before it's used the first time to ensure consistent behavior.");
            }
            EventBus.defaultInstance = build();
            return EventBus.defaultInstance;
        }
    }

    /** Builds an EventBus based on the current configuration. */
    public EventBus build() {
        return new EventBus(this);
    }

上面通过build方法,以当前EventBusBuilder对象作为参数生成EventBus单例对象,并赋值给defaultInstance,这样就把subscriberInfoIndexes信息传递给了EventBus。以后调用EventBus getDefault()返回的就是这里生成的单例对象,里面包含了subscriberInfoIndexes信息。

而且在Application中生成了 EventBus 的默认单例,这样就保证了在项目其它地方执行EventBus.getDefault()就能得到就是上面包含subscriberInfoIndexes信息的单例。

在上面分析查找注解函数的时候,分析过一个函数:

    private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            findState.subscriberInfo = getSubscriberInfo(findState);
            if (findState.subscriberInfo != null) {
                ····
            } else {
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }

如果没有使用注解处理器的话getSubscriberInfo这个方法返回值是null,因此会走到findUsingReflectionInSingleClass,通过反射区获取注解方法。现在使用使用注解处理器的话在重新看下这个函数。

    private SubscriberInfo getSubscriberInfo(FindState findState) {
        if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
            SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
            if (findState.clazz == superclassInfo.getSubscriberClass()) {
                return superclassInfo;
            }
        }
        //不为空
        if (subscriberInfoIndexes != null) {
            for (SubscriberInfoIndex index : subscriberInfoIndexes) {
                SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
                if (info != null) {
                    return info;
                }
            }
        }
        return null;
    }

    @Override
    public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {
        SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
        if (info != null) {
            return info;
        } else {
            return null;
        }
    }

如果使用了注解处理器,因为subscriberInfoIndexes这个集合不为空,遍历获取当前类对应的注解方法列表, index.getSubscriberInfo这个方法实际调用的就是系统生成的MyEventBusIndex中的getSubscriberInfo方法,这样就获取到了之前编译生成的注解方法。

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

通过getSubscriberInfo返回当前类所有注解方法后,遍历所有订阅了事件的方法然后加入到subscriberMethods列表中,其它的和之前的注册流程一样。

参考文章:
EventBus 原理解析文章来源地址https://www.toymoban.com/news/detail-628404.html

到了这里,关于EventBus 开源库学习(三)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Go语言EventBus

    EventBus是GoLang的小型轻量级事件总线,具有异步兼容性。 类似于观察者模式和发布订阅模式。 GitHub地址: https://github.com/asaskevich/EventBus 官方文档: https://pkg.go.dev/github.com/asaskevich/EventBus 1.1 安装 1.2 使用 进行封装: 订阅多个: Subscribe 可以放在 init 函数中: New() Subscribe() Su

    2024年02月11日
    浏览(34)
  • SpringBoot - Google EventBus、AsyncEventBus

    EventBus 顾名思义,事件总线,是一个轻量级的发布/订阅模式的应用模式,最初设计及应用源与 google guava 库。 相比于各种 MQ 中间件更加简洁、轻量,它可以在单体非分布式的小型应用模块内部使用(即同一个JVM范围)。 我们也可以把它和 MQ 中间件结合起来使用,使用 Even

    2024年02月10日
    浏览(32)
  • 微信小程序全局事件订阅eventBus

    微信小程序全局事件订阅 在Vue开发中,我们可能用过eventBus来解决全局范围内的事件订阅及触发逻辑,在微信小程序的开发中我们可能也也会遇到同样的需求,那么我们尝试下在小程序(原生小程序开发)中实现类似eventBus的事件订阅功能。 全局事件订阅 全局实例 在Vue中我

    2024年02月12日
    浏览(40)
  • flutter开发实战-事件总线EventBus实现

    flutter开发实战-事件总线EventBus实现 在开发中,经常会需要一个广播机制,用以跨Widget事件通知。 事件总线 实现了订阅者模式,订阅者模式包含发布者和订阅者两种角色,可以通过事件总线来触发事件和监听事件。 实现eventBus 在工程的pubspec.yaml引入库 1.使用event_bus库 创建一

    2024年02月15日
    浏览(43)
  • React V6实现类似与vue的eventBus

    功能背景 想要实现类似于vue的eventBus的功能,由一个组件通知其他一个或多个组件。应用场景:比如一个可视化大屏的界面,当筛选条件变化的时候,要同时通知到大屏中所有图表一起变化。(当然使用store也是可以的,eventbus就是相当于多了一个解决方案) 代码实现 eventB

    2024年02月11日
    浏览(48)
  • 选择 Guava EventBus 还是 Spring Framework ApplicationEvent

    文章首发地址 Spring Framework 的 ApplicationEvent 是 Spring 框架提供的一种事件机制,用于实现发布和订阅事件的功能。它基于观察者模式,允许应用程序内的组件之间进行松耦合的通信。 下面是关于 Spring Framework 的 ApplicationEvent 的详解: 事件定义: ApplicationEvent 是一个抽象类,用

    2024年02月09日
    浏览(39)
  • SpringBoot中间件使用之EventBus、Metric、CommandLineRunner

    1、EventBus 使用EventBus 事件总线的方式可以实现消息的 发布/订阅 功能,EventBus是一个轻量级的消息服务组件,适用于Android和Java。 // 1.注册事件通过 EventBus.getDefault().register(); // 2.发布事件 EventBus.getDefault().post(“事件内容”); // 3.监听事件,通过在方法上添加注解 @Subscribe实现

    2024年02月13日
    浏览(43)
  • 观察者模式(下):如何实现一个异步非阻塞的EventBus框架?

    上一节课中,我们学习了观察者模式的原理、实现、应用场景,重点介绍了不同应用场景下,几种不同的实现方式,包括:同步阻塞、异步非阻塞、进程内、进程间的实现方式。 同步阻塞是最经典的实现方式,主要是为了代码解耦;异步非阻塞除了能实现代码解耦之外,还能

    2024年02月16日
    浏览(37)
  • .NET6 项目使用RabbitMQ实现基于事件总线EventBus通信

    一、概念及介绍         通常通过使用事件总线实现来执行此发布/订阅系统。 事件总线可以设计为包含 API 的接口,该 API 是订阅和取消订阅事件和发布事件所需的。 它还可以包含一个或多个基于跨进程或消息通信的实现,例如支持异步通信和发布/订阅模型的消息队列或

    2024年04月28日
    浏览(53)
  • 探索前端跨组件通信:EventBus在Vue和React中的应用

    本文作者系360奇舞团前端开发工程师 事件总线(Event Bus) 是一种用于组件间通信的模式,通常用于解决组件之间的解耦和简化通信的问题。在前端框架中,如 Vue.js,事件总线是一个常见的概念。基本上,事件总线是一个能够触发和监听事件的机制,使得组件能够在不直接依

    2024年02月02日
    浏览(70)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包