当前位置: 代码迷 >> 综合 >> EventBus-3.1.1源码阅读
  详细解决方案

EventBus-3.1.1源码阅读

热度:118   发布时间:2023-09-06 12:46:17.0

1. 注册及查找事件

1.1 EventBus初始化

  • getDefault: 通过单例模式获取实例,同时里面采用Builder模式构造部分初始化参数,方便定制部分配置信息
    //Builder模式,在EventBusBuilder里面完成一些默认的初始化操作
    private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();public static EventBus getDefault() {//通过DCL单例模式创建EventBus实例
    }public EventBus() {this(DEFAULT_BUILDER);
    }EventBus(EventBusBuilder builder) {//通过EventBusBuilder完成的初始化构造
    }
    

1.2 EventBus注册

  • register:根据订阅者类信息,查询对应的订阅方法信息,遍历注册订阅方法

    public void register(Object subscriber) {//根据订阅者的类名信息查询订阅方法Class<?> subscriberClass = subscriber.getClass();List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);synchronized (this) {//遍历并注册这些订阅方法for (SubscriberMethod subscriberMethod : subscriberMethods) {subscribe(subscriber, subscriberMethod);}}
    }
    
  • SubscriberMethod:封装了订阅方法的基本类型信息,即@Subscribe中所注解的内容

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

1.3 查询订阅者所有的订阅方法

  • findSubscriberMethods: 查询订阅者所有的订阅方法,三种查询方式:缓存,通过注解器索引,反射

    //METHOD_CACHE缓存了订阅及其所有订阅方法
    private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();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 {subscriberMethods = findUsingInfo(subscriberClass);//通过注解的方式}if (subscriberMethods.isEmpty()) {//如果当前订阅者没有声明订阅方法,则抛出异常} else {//将订阅者及订阅方法存入缓存中METHOD_CACHE.put(subscriberClass, subscriberMethods);...}
    }
    

1.3.1 通过注解索引的方式获取订阅者的订阅方法

  • findUsingInfo:获取订阅者信息,并且对其父类进行向上查询,最后将所有订阅方法信息封装到subscriberMethods列表中返回

     private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {FindState findState = prepareFindState();//通过对象池的方式复用FindStatefindState.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.clazz改为subscriberClass的父类Class,再进行遍历findState.moveToSuperclass();}return getMethodsAndRelease(findState);//回收FindState对象到对象池中,并返回subscriberMethods列表
    }...
    //实现对象池
    private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];// POOL_SIZE = 4;
    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();
    }
  • 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;
    }
    
  • FindState 主要用来辅助存储订阅者信息

    static class FindState {final List<SubscriberMethod> subscriberMethods = new ArrayList<>();final Map<Class, Object> anyMethodByEventType = new HashMap<>();final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();final StringBuilder methodKeyBuilder = new StringBuilder(128);...void moveToSuperclass() { ... }// 修改findState.clazz为subscriberClass的父类Class
    }  
    

1.3.2 通过反射获取订阅者的订阅方法

  • findUsingReflection

    //FindState主要用来辅助存储订阅者信息
    private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {FindState findState = prepareFindState();//通过对象池的方式复用FindStatefindState.initForSubscriber(subscriberClass);//初始化参数并将订阅者类信息导入while (findState.clazz != null) {findUsingReflectionInSingleClass(findState);//通过反射查询订阅者的订阅方法// 将findState.clazz改为subscriberClass的父类Class,再进行遍历findState.moveToSuperclass();}return getMethodsAndRelease(findState);//回收FindState对象到对象池中,并返回subscriberMethods列表
    }
  • findUsingReflectionInSingleClass:通过反射查询订阅者的订阅方法

    private void findUsingReflectionInSingleClass(FindState findState) {Method[] methods;try {// This is faster than getMethods, especially when subscribers are fat classes like Activitiesmethods = findState.clazz.getDeclaredMethods();//获取所有声明方法} catch (Throwable th) {// Workaround for java.lang.NoClassDefFoundErrormethods = findState.clazz.getMethods();findState.skipSuperClasses = true;}for (Method method : methods) {int modifiers = method.getModifiers();//校验方法修饰属性,是否PUBLIC及MODIFIERS_IGNORE// MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC;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)) {//抛出异常}} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {//抛出异常}}
    }
    

1.4 注册订阅方法:

  • subscribe:将订阅者和订阅方法封装成对象,并将相同事件类型的封装对象根据事件优先级封装到CopyOnWriteArrayList集合中,再将事件类型和CopyOnWriteArrayList封装到map集合中

    Map<Object, List<Class<?>>> typesBySubscriber;
    Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
    Map<Class<?>, Object> stickyEvents = new ConcurrentHashMap<>();private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {Class<?> eventType = subscriberMethod.eventType;//将订阅者和订阅方法封装成对象Subscription newSubscription = new Subscription(subscriber, subscriberMethod);//查询出同样事件类型的所有Subscription对象CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);//通过CopyOnWriteArrayList对订阅事件对象按事件类型,按照优先级进行存储(同优先级则插入末尾),并校验是否多次注册(已注册抛出异常)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;}}//将订阅者对象和订阅事件存储对应存储到map集合中List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);if (subscribedEvents == null) {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);}}
    }
    

2. 发布通知消息

  • post:通过在ThreadLocal中封装一个事件队列,去添加和执行相应的事件

    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;}}
    }
    private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {@Overrideprotected PostingThreadState initialValue() {return new PostingThreadState();}};
    
  • 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);}... //找不到事件时异常处理 NoSubscriberEvent
    }private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {CopyOnWriteArrayList<Subscription> subscriptions;synchronized (this) {//获取对应的订阅者subscriptions = subscriptionsByEventType.get(eventClass);}...for (Subscription subscription : subscriptions) {postingState.event = event;postingState.subscription = subscription;boolean aborted = false;try {//通知订阅者postToSubscription(subscription, event, postingState.isMainThread);aborted = postingState.canceled;} finally {...//重置postingState属性}if (aborted)break;}...}
    
  • 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继承自HandlermainThreadPoster.enqueue(subscription, event);}break;case MAIN_ORDERED:if (mainThreadPoster != null) {mainThreadPoster.enqueue(subscription, event);} else {invokeSubscriber(subscription, event);}break;case BACKGROUND:if (isMainThread) {//如果不是后台线程,则加入到后台线程行队列中执行backgroundPoster.enqueue(subscription, event);} else {invokeSubscriber(subscription, event);}break;case ASYNC:asyncPoster.enqueue(subscription, event);break;...}
    }
    ...
    void invokeSubscriber(Subscription subscription, Object event) {...subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
    }

3. 发布粘性通知

  • postSticky: 粘性事件会通过单独的stickyEvents集合进行存储,同时会在事件订阅的时候进行check post,继而实现粘性这一效果

     public void postSticky(Object event) {synchronized (stickyEvents) {stickyEvents.put(event.getClass(), event);//添加到粘性事件列表,在上述注册订阅方法时,会通过列表去通知信息}// Should be posted after it is putted, in case the subscriber wants to remove immediatelypost(event);//发布通知,当前已经订阅的订阅者可以收到}...private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {...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);}}
    }