EventBus3 源码解读

基本概念

EventBus是一款针对Android优化的发布/订阅事件总线库。简便了Activities, Fragments, 以及background threads之间的通信,使发送者与订阅者之间有效解耦。

基本使用

EventBus的使用也极其简单,只需三步即可。

  1. 定义一个事件类型。

     public class MessageEvent {
     public final String message;
     public MessageEvent(String message) {
        this.message = message;
     }
    }
  2. 准备订阅者

    只需给一个public方法添加@Subscribe注解,那么当发布事件时,订阅者就能匹配并接受处理事件。

    // This method will be called when a MessageEvent is posted
    @Subscribe
    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);
    }

    所有的订阅者都应该在事件总线中被注册。只有被注册的订阅者才能收到事件。

    @Override
    public void onStart() {
        super.onStart();
     EventBus.getDefault().register(this);
    }
    
    @Override
    public void onStop() {
      EventBus.getDefault().unregister(this);
     super.onStop();
    }
  3. 发布事件

    你可以在代码的任何地方发布事件,所有更当前事件类型匹配的订阅者都可以接收到这个事件。

     EventBus.getDefault().post(new MessageEvent("Hello everyone!"));

EventBus是一个非常小巧的库,但是功能却足够强大,接下来去源码里看看。

源码解读

我们从EventBus.getDefault().register(this);这一行开始,看看getDefault()做了什么?

    public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }

可以看出,保持了一个单例。EventBus的构造方法如下。

    //=================这两个集合很重要,后面经常出现 START========================

    //key为事件类型,value为订阅关系列表。用于查询订阅了该事件的所有订阅关系列表,下称事件类型集合
    private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
    //key为订阅者,value为订阅者中的事件类型列表。用于查询该订阅者订阅了的事件。下称订阅者集合
    private final Map<Object, List<Class<?>>> typesBySubscriber;

     //=======================这两个集合很重要,后面经常出现 END==================

    //粘性事件,只保留最近一次的事件(相同事件类型只保留一次)
    private final Map<Class<?>, Object> stickyEvents;
    //存放SubscriberInfo索引
    private List<SubscriberInfoIndex> subscriberInfoIndexes;
    //事件类型缓存,key为事件类型,value为当前事件类型继承的所有事件类型
    private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();

    //主线程发布者
    private final HandlerPoster mainThreadPoster;
    //子线程发布者(串行)
    private final BackgroundPoster backgroundPoster;
    //子线程发布者(另开一个线程)
    private final AsyncPoster asyncPoster;
    //订阅方法查找器
    private final SubscriberMethodFinder subscriberMethodFinder;
    //线程池,用于在子线程中发布事件
    private final ExecutorService executorService;

    private final boolean throwSubscriberException;
    private final boolean logSubscriberExceptions;
    private final boolean logNoSubscriberMessages;
    private final boolean sendSubscriberExceptionEvent;
    private final boolean sendNoSubscriberEvent;
    private final boolean eventInheritance;

    private final int indexCount;

    public EventBus() {
        this(DEFAULT_BUILDER);
    }

    //构造方法
    EventBus(EventBusBuilder builder) {
        //初始化事件类型集合
        subscriptionsByEventType = new HashMap<>();
        //初始化订阅者集合
        typesBySubscriber = new HashMap<>();
        //粘性事件集合
        stickyEvents = new ConcurrentHashMap<>();
        //主线程发布者
        mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
        //子线程发布者(串行,保持只有一个线程)
        backgroundPoster = new BackgroundPoster(this);
        //子线程发布者(并行,新起一个线程)
        asyncPoster = new AsyncPoster(this);

        //以下通过EventBusBuilder进行赋值
        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;
    }

代码有点长,看的可能有点晕,从源码可以看出最终构造方法中会传入EventBusBuilder对象进行赋值初始化,EventBusBuilder用来配置信息。构造方法主要就是初始化环境。

注册事件

我们现在就来看看register中的源码。

    public void register(Object subscriber) {
        //获取Class对象
        Class<?> subscriberClass = subscriber.getClass();
        //通过方法查找器寻找该订阅者中的订阅方法。
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                 //加入到集合中保存
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

代码很简练,思路也比较清晰。首先获取订阅者的Class对象,然后通过订阅者方法查找器(SubscriberMethodFinder)查询该订阅者中的订阅方法并返回,最后通过subscribe存入到相关集合中。

在介绍SubscriberMethodFinder之前我们先来了解一下其他几个类。

Subscribe注解

Subscribe用来给订阅方法进行注解,可以指定线程模型,优先级,是否粘性等等。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
    ThreadMode threadMode() default ThreadMode.POSTING;
    boolean sticky() default false;
    int priority() default 0;
}

ThreadMode(线程模型)

ThreadMode是个枚举类,可以指定四种线程模型。

public enum ThreadMode {
    //表示在哪个线程发布事件就在哪个线程接收事件
    POSTING,
    //表示在主线程接收事件
    MAIN,
    //表示在子线程接收事件
    BACKGROUND,
    //表示开启一个线程接收事件
    ASYNC
}

SubscriberMethod(订阅者方法)

通过类名就可以猜出这个类肯定是用来包装订阅方法的,里面存放了方法、线程模型、事件类型(订阅方法中那个参数类型),优先级、是否粘性等。

public class SubscriberMethod {
    final Method method;//订阅方法
    final ThreadMode threadMode;//线程模型
    final Class<?> eventType;//事件类型(就是订阅方法的参数类型)
    final int priority;//优先级
    final boolean sticky;//是否粘性

    public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) {
        this.method = method;
        this.threadMode = threadMode;
        this.eventType = eventType;
        this.priority = priority;
        this.sticky = sticky;
    }
     //..
     //省略部分源码
}

FindState

FindState是一个临时存储订阅方法的类,在查找完毕后就会被回收。

    static class FindState {
        //存储订阅方法的集合
        final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
        //根据事件类型存储订阅方法,用来判断是不是该事件已经被添加过了
        final Map<Class, Object> anyMethodByEventType = new HashMap<>();
        //根据方法名生成的key存储订阅者的类
        final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
        //方法key生成器
        final StringBuilder methodKeyBuilder = new StringBuilder(128);

        Class<?> subscriberClass;//订阅者的父类
        Class<?> clazz;//当前订阅者
        boolean skipSuperClasses;//是否跳过父类
        SubscriberInfo subscriberInfo;//这个用于注解生成器

       //初始化FindState
        void initForSubscriber(Class<?> subscriberClass) {
            this.subscriberClass = clazz = subscriberClass;
            skipSuperClasses = false;
            subscriberInfo = null;
        }

      //回收FindState
        void recycle() {
            subscriberMethods.clear();
            anyMethodByEventType.clear();
            subscriberClassByMethodKey.clear();
            methodKeyBuilder.setLength(0);
            subscriberClass = null;
            clazz = null;
            skipSuperClasses = false;
            subscriberInfo = null;
        }
       //..
       //省略了部分源码
    }

Subscription

Subscription表示订阅关系,由订阅者和订阅者方法构成。

final class Subscription {
    final Object subscriber;//订阅者
    final SubscriberMethod subscriberMethod;//订阅者方法

    volatile boolean active;

    Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
        this.subscriber = subscriber;
        this.subscriberMethod = subscriberMethod;
        active = true;
    }
   //..
   //省略了部分源码
}

注册事件

现在我们回过头来看看SubscriberMethodFinder的findSubscriberMethods方法。

    List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        //看看集合中有没有缓存
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }

        //是否忽略注解器生成的Index类
        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;
        }
    }

一般如果不引用注解生成器,就会直接走反射查找这个路线。

    private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
        //获取一个临时保存订阅信息的FindState类
        FindState findState = prepareFindState();
        //初始化基本信息(其实就是把subscriberClass赋值给findState.clazz)
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
             //查找订阅方法
            findUsingReflectionInSingleClass(findState);
            //定位到父类(就是把父类赋值给findState.clazz,默认跳过系统类)
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);//从FindState类中取出方法集合,然后释放资源。
    }

默认会保持4个FindState循环利用,prepareFindState就是取出一个FindState。然后通过findUsingReflectionInSingleClass将订阅方法集合暂时保存在FindState中。

   private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        try {
            //反射获取方法
            methods = findState.clazz.getDeclaredMethods();
        } catch (Throwable th) {
            methods = findState.clazz.getMethods();
            findState.skipSuperClasses = true;
        }
         //循环遍历所有的方法
        for (Method method : methods) {
            int modifiers = method.getModifiers();//获取修饰符
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {//必须为public
                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)) {
                            //获取线程模型等信息
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            //添加到FindState中的subscriberMethods集合类
                            findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                    subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                        }
                    }
                }
                //...
                //省略了else中的代码
        }
    }

findUsingReflectionInSingleClass方法主要用于遍历匹配方法,如果满足条件就添加到FindState中的subscriberMethods集合进行保存。既然订阅方法已经遍历完了,那么现在我们回到register方法中。

可以看出会对每个方法进行遍历然后执行subscribe

    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        //获取事件类型(就是方法里的那个参数类型)
        Class<?> eventType = subscriberMethod.eventType;
         //用Subscription包装subscriberMethod,可以看出将订阅者与订阅方法给关联了起来。
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);

        //看看事件类型集合里是不是存在过之前的事件类型( CopyOnWriteArrayList是线程安全的)
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions == null) {//没有当前事件类型的集合
            //第一次须初始化列表
            subscriptions = new CopyOnWriteArrayList<>();
            //subscriptions为空表示之前没有相同的类型,那么现在就塞进去
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
            //subscriptions不为空说明有相同事件类型的,判断列表里是不是已经包含了,包含就抛出异常
            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) {
           //没有就给当前订阅者new个事件列表放进去
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }

        //当到该订阅者下的事件列表里
        subscribedEvents.add(eventType);

        //判断是不是粘性方法
        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);
            }
        }
    }

代码有点长,但是逻辑并不复杂,可以看出把订阅方法循环添加到了集合中。然后检查有没有粘性方法,如果有就将最近一次的粘性事件发布即可。

解除事件

接下来看解除事件,为什么不先看发布事件?因为注册和解除是互相呼应的,而且比较简单。趁热看,免得之后又被几个集合给搞懵逼了(说的就是我)。

    public synchronized void unregister(Object subscriber) {
        //根据订阅者查询该订阅者有哪些事件
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            for (Class<?> eventType : subscribedTypes) {
                 //从事件类型集合中移除
                unsubscribeByEventType(subscriber, eventType);
            }
            //从订阅者集合中移除
            typesBySubscriber.remove(subscriber);
        } else {
            Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }

我们知道,注册事件时会将订阅者以及订阅事件保存到集合中,那么解除事件毋容置疑,首先去集合中查询有没有,如果有,把它从事件类型集合中移除,然后从订阅者集合中移除。unsubscribeByEventType源码如下。

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

发布事件

发布事件用ThreadLocal保存了PostingThreadState,PostingThreadState是一个保存事件的类。然后通过循环发送单个事件,可以看出发布事件是串行执行的。

    /** Posts the given event to the event bus. */
    public void post(Object event) {
       //PostingThreadState类似于FindState,用于保存要发布的事件,里面有一个事件队列
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);//添加到事件队列中

        if (!postingState.isPosting) {
            postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
            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;
            }
        }
    }

PostingThreadState的源码如下。

    final static class PostingThreadState {
        final List<Object> eventQueue = new ArrayList<Object>();//事件列表
        boolean isPosting;//是否正在发布事件
        boolean isMainThread;//是否在主线程
        Subscription subscription; //订阅关系
        Object event; //事件
        boolean canceled;//是否已被取消
    }

接下来看看postSingleEvent方法。如果可以响应事件继承就获取当前事件类型的所有父类。然后逐个发布事件。

    private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();//获取事件类型
        boolean subscriptionFound = 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);
        }
        //..
        //省略了部分源码
    }

可以看出,最终通过postSingleEventForEventType来发布事件。

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

postToSubscription中即是根据订阅关系发布事件。根据不同的线程模型使用不同发布者进行发布。

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

最终通过反射发布事件。我们只来看一下POSTING源码。其他就不赘述了,操作基本大同小异。

    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工作流程已经梳理完毕。

最后

  • 那个注解生成器是什么鬼?

注解生成器,就是在编译的时候根据注解生成特定的类。就跟自己写的源码一样,执行效率比反射要高很多。

我们在分析subscriberMethodFinder.findSubscriberMethods查找方法时,提到一般只会走反射,所以没有关心通过注解生成器查找的步骤。

        //是否忽略注解器生成的Index类
        if (ignoreGeneratedIndex) {
            //通过反射查找
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
           //通过注解生成器生成的类查找
            subscriberMethods = findUsingInfo(subscriberClass);
        }

现在我们来看下findUsingInfo源码。

    private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        //初始化FindState
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            findState.subscriberInfo = getSubscriberInfo(findState);//获取注解器生成的SubscriberInfo
            if (findState.subscriberInfo != null) {
                //如果找到了SubscriberInfo就获取方法
                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);
    }

SubscriberInfo信息如下。

public interface SubscriberInfo {
    Class<?> getSubscriberClass();//获取父类

    SubscriberMethod[] getSubscriberMethods();//获取订阅方法

    SubscriberInfo getSuperSubscriberInfo();//获取父类订阅者信息

    boolean shouldCheckSuperclass();
}

getSubscriberInfo用来根据订阅者获取SubscriberInfo。

    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;
            }
        }
        //SubscriberInfoIndex中获取SubscriberInfo
        if (subscriberInfoIndexes != null) {
            for (SubscriberInfoIndex index : subscriberInfoIndexes) {
                SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
                if (info != null) {
                    return info;
                }
            }
        }
        return null;
    }

EventBus中注解生成器生成代码。

   private void createInfoIndexFile(String index) {
        BufferedWriter writer = null;
        try {
            JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(index);
            int period = index.lastIndexOf(‘.‘);
            String myPackage = period > 0 ? index.substring(0, period) : null;
            String clazz = index.substring(period + 1);
            writer = new BufferedWriter(sourceFile.openWriter());
            if (myPackage != null) {
                writer.write("package " + myPackage + ";\n\n");
            }
            writer.write("import org.greenrobot.eventbus.meta.SimpleSubscriberInfo;\n");
            writer.write("import org.greenrobot.eventbus.meta.SubscriberMethodInfo;\n");
            writer.write("import org.greenrobot.eventbus.meta.SubscriberInfo;\n");
            writer.write("import org.greenrobot.eventbus.meta.SubscriberInfoIndex;\n\n");
            writer.write("import org.greenrobot.eventbus.ThreadMode;\n\n");
            writer.write("import java.util.HashMap;\n");
            writer.write("import java.util.Map;\n\n");
            writer.write("/** This class is generated by EventBus, do not edit. */\n");
            writer.write("public class " + clazz + " implements SubscriberInfoIndex {\n");
            writer.write("    private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;\n\n");
            writer.write("    static {\n");
            writer.write("        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();\n\n");
            writeIndexLines(writer, myPackage);
            writer.write("    }\n\n");
            writer.write("    private static void putIndex(SubscriberInfo info) {\n");
            writer.write("        SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);\n");
            writer.write("    }\n\n");
            writer.write("    @Override\n");
            writer.write("    public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {\n");
            writer.write("        SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);\n");
            writer.write("        if (info != null) {\n");
            writer.write("            return info;\n");
            writer.write("        } else {\n");
            writer.write("            return null;\n");
            writer.write("        }\n");
            writer.write("    }\n");
            writer.write("}\n");
        } catch (IOException e) {
            throw new RuntimeException("Could not write source for " + index, e);
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    //Silent
                }
            }
        }
    }

writeIndexLines写入订阅者相关的订阅方法信息

    private void writeIndexLines(BufferedWriter writer, String myPackage) throws IOException {
        for (TypeElement subscriberTypeElement : methodsByClass.keySet()) {
            if (classesToSkip.contains(subscriberTypeElement)) {
                continue;
            }

            String subscriberClass = getClassString(subscriberTypeElement, myPackage);
            if (isVisible(myPackage, subscriberTypeElement)) {
                writeLine(writer, 2,
                        "putIndex(new SimpleSubscriberInfo(" + subscriberClass + ".class,",
                        "true,", "new SubscriberMethodInfo[] {");
                List<ExecutableElement> methods = methodsByClass.get(subscriberTypeElement);
                writeCreateSubscriberMethods(writer, methods, "new SubscriberMethodInfo", myPackage);
                writer.write("        }));\n\n");
            } else {
                writer.write("        // Subscriber not visible to index: " + subscriberClass + "\n");
            }
        }
    }

大家只要知道注解生成器是用来干嘛的就行了,关于注解生成器的原理和使用方法,改篇再作深究,有兴趣的可以自行查阅AnnotationProcessor资料。

时间: 2024-10-12 15:30:57

EventBus3 源码解读的相关文章

QCustomplot使用分享(二) 源码解读

一.头文件概述 从这篇文章开始,我们将正式的进入到QCustomPlot的实践学习中来,首先我们先来学习下QCustomPlot的类图,如果下载了QCustomPlot源码的同学可以自己去QCustomPlot的目录下documentation/qcustomplot下寻找一个名字叫做index.html的文件,将其在浏览器中打开,也是可以找到这个库的类图.如图1所示,是组成一个QCustomPlot类图的可能组成形式. 一个图表(QCustomPlot):包含一个或者多个图层.一个或多个ite

vue源码解读预热-0

vueJS的源码解读 vue源码总共包含约一万行代码量(包括注释)特别感谢作者Evan You开放的源代码,访问地址为Github 代码整体介绍与函数介绍预览 代码模块分析 代码整体思路 总体的分析 从图片中可以看出的为采用IIFE(Immediately-Invoked Function Expression)立即执行的函数表达式的形式进行的代码的编写 常见的几种插件方式: (function(,){}(,))或(function(,){})(,)或!function(){}()等等,其中必有

SpringMVC源码解读 - RequestMapping注解实现解读 - RequestCondition体系

一般我们开发时,使用最多的还是@RequestMapping注解方式. @RequestMapping(value = "/", param = "role=guest", consumes = "!application/json") public void myHtmlService() { // ... } 台前的是RequestMapping ,正经干活的却是RequestCondition,根据配置的不同条件匹配request. @Re

jdk1.8.0_45源码解读——HashMap的实现

jdk1.8.0_45源码解读——HashMap的实现 一.HashMap概述 HashMap是基于哈希表的Map接口实现的,此实现提供所有可选的映射操作.存储的是<key,value>对的映射,允许多个null值和一个null键.但此类不保证映射的顺序,特别是它不保证该顺序恒久不变.  除了HashMap是非同步以及允许使用null外,HashMap 类与 Hashtable大致相同. 此实现假定哈希函数将元素适当地分布在各桶之间,可为基本操作(get 和 put)提供稳定的性能.迭代col

15、Spark Streaming源码解读之No Receivers彻底思考

在前几期文章里讲了带Receiver的Spark Streaming 应用的相关源码解读,但是现在开发Spark Streaming的应用越来越多的采用No Receivers(Direct Approach)的方式,No Receiver的方式的优势: 1. 更强的控制自由度 2. 语义一致性 其实No Receivers的方式更符合我们读取数据,操作数据的思路的.因为Spark 本身是一个计算框架,他底层会有数据来源,如果没有Receivers,我们直接操作数据来源,这其实是一种更自然的方式

jdk1.8.0_45源码解读——Set接口和AbstractSet抽象类的实现

jdk1.8.0_45源码解读——Set接口和AbstractSet抽象类的实现 一. Set架构 如上图: (01) Set 是继承于Collection的接口.它是一个不允许有重复元素的集合.(02) AbstractSet 是一个抽象类,它继承于AbstractCollection.AbstractCollection实现了Set中的绝大部分函数,为Set的实现类提供了便利.(03) HastSet 和 TreeSet 是Set的两个实现类.        HashSet依赖于HashMa

线程本地变量ThreadLocal源码解读

  一.ThreadLocal基础知识   原始线程现状: 按照传统经验,如果某个对象是非线程安全的,在多线程环境下,对对象的访问必须采用synchronized进行线程同步.但是Spring中的各种模板类并未采用线程同步机制,因为线程同步会影响并发性和系统性能,而且实现难度也不小. ThreadLocal在Spring中发挥着重要的作用.在管理request作用域的bean,事务管理,任务调度,AOP等模块中都出现了它的身影. ThreadLocal介绍: 它不是一个线程,而是线程的一个本地化

hadoop源码解读namenode高可靠:HA;web方式查看namenode下信息;dfs/data决定datanode存储位置

点击browserFilesystem,和命令查看结果一样 当我们查看hadoop源码时,我们看到hdfs下的hdfs-default.xml文件信息 我们查找${hadoop.tmp.dir}这是引用变量,肯定在其他文件有定义,在core-default.xml中查看到,这两个配置文件有个共同点: 就是不要修改此文件,但可以复制信息到core-site.xml和hdfs-site.xml中修改 usr/local/hadoop 是我存放hadoop文件夹的地方 几个关于namenode的重要文

Jfinal启动源码解读

本文对Jfinal的启动源码做解释说明. PS:Jfinal启动容器可基于Tomcat/Jetty等web容器启动,本文基于Jetty的启动方式做启动源码的解读和分析,tomcat类似. 入口  JFinalConfig的继承类的Main方法为入口,实例代码继承类为:DemoConfig,Main方法如下: public static void main(String[] args) { /** * 特别注意:Eclipse 之下建议的启动方式 */ JFinal.start("WebRoot&