EventBus

作者: 拿拿guardian | 来源:发表于2020-03-18 18:21 被阅读0次

一、两个主要方法register和post。

register方法参数是当前类,找到当前类所有订阅的方法(@Subscribe注解、public声明、参数个数为1、非abstract、static)。如果没有用事先添加索引,这一步是需要用到反射的。索引是编译期间构建一个类,里面是一个静态的HashMap,key是订阅过的类,value是该类的SubscriberInfod对象,包含所有订阅的方法,ThreadMode,事件类型EventType等。
(如何添加索引 https://blog.csdn.net/z609933542/article/details/50953166

找到所有订阅的方法后,挨个执行subscribe方法。核心是两个HashMap:
1.subscriptionsByEventType, key是事件类型eventType,value是Subscription对象(包含订阅类和订阅了该事件的类的方法)
2.typesBySubscriber,key是订阅类,value是该类订阅的所有事件集。

第一个HashMap用来通过事件寻找订阅者并分发事件;
第二个HashMap用来判断当前类是否已经注册过和取消注册。

执行subscribe方法的过程就是往这两个HashMap添加Key-Value的过程。

post方法参数是具体事件,过程简化了说就是通过subscriptionsByEventType查找所有订阅了改事件Subscription对象,挨个分发事件。
线程切换根据threadMode注解,通过各种Poster实现。

试想一下,如果你要手动撸一个EventBus,要怎么做?
每个类可能订阅一个或者几个事件,每个事件可能要发送给一个或者多个类。订阅的过程,就是通过类寻找订阅事件的过程,并建立 类->事件,事件->类两个映射HashMap;事件发送的过程就是通过具体事件寻找订阅者(也就是类)并挨个分发的过程。

==========================

二、关于反射
1.post找到订阅方法后分发给订阅者执行(invokeSubscriber)会用到反射(subscription.subscriberMethod.method.invoke(subscription.subscriber, event))
2.如果没有添加过索引,那么注册的过程中遍历类的方法会用到反射;

所以EventBus一定会用到反射,性能方面是有影响的。

==========================

三、关于跨线程
EventBusBuilder内部有个DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool()线程池,通过该线程池实现跨线程调度。

四、关于跨进程
EventBus不支持跨进程。跨进程可以参考升级版HermesEventBus。
EventBus主要用来模块/组件间解耦,本身不是为了跨进程设计的。想要用它来跨进程,就好比用杀鸡刀去杀牛,是不合适的。
在一个跨进程的场景下,如果你优先想到的方案是EventBus,那说明你的思路有问题。

五、优劣
优点:解耦,代码开发方便
缺点:需要定义大量的Event类、用到了反射、注解方法不能被混淆

六、内存泄漏
EventBus注册后如果没有取消注册,可能会内存泄漏。因为EventBus.register方法产生的中间对象会持有当前Class的实例。

    public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class<?> eventType = subscriberMethod.eventType;
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        ...
    }
final class Subscription {
    final Object subscriber;
    final SubscriberMethod subscriberMethod;
    /**
     * Becomes false as soon as {@link EventBus#unregister(Object)} is called, which is checked by queued event delivery
     * {@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions.
     */
    volatile boolean active;

    Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
        this.subscriber = subscriber;
        this.subscriberMethod = subscriberMethod;
        active = true;
    }
    ...

构造的Subscription对象的subscriber会指向注册时的Class对象。

相关文章

网友评论

      本文标题:EventBus

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