java

Guava eventBus 关于@AllowConcurren

2017-10-26  本文已影响204人  guli_2018

背景

以下带有@Subscribe的方法简称订阅方法。
@AllowConcurrentEvents的作用就是当使用多线程模式的时候,标记订阅的方法是线程安全的。使之EventBus可以针对同个subscribe方法进行多线程。简单链接:http://www.cnblogs.com/whitewolf/p/4132840.html

经历

但当@Subscribe方法存在继承逻辑时,坑就出现了。荔枝:

package eh;

import com.google.common.eventbus.AllowConcurrentEvents;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;

/**
 * Created by shenhj on 2017/10/26.
 */
public class EventBusTest {

    public static void main(String[] args) {
        EventBus eventBus = new EventBus();
        eventBus.register(new EventListener1());
        eventBus.post(1);
        eventBus.post(1L);
        eventBus.post("hello");
    }
    public static class EventListener1 implements EventListener{
        public void listenInteger(Integer i) {//此方法不会被加入eventBus的loadingCache,父类方法取代之
            System.out.println(i);
        }
        @Subscribe
        public void listenLong(Long l) {//此方法取代父类方法加入eventBus的loadingCache
            System.out.println(l);
        }
        @Subscribe
        @AllowConcurrentEvents
        public void listenString(String string) {//此方法取代父类方法加入eventBus的loadingCache
            System.out.println(string);
        }
    }
    public  interface EventListener {
        @Subscribe
        @AllowConcurrentEvents
        void listenInteger(Integer i);

        @Subscribe
        @AllowConcurrentEvents
        void listenLong(Long i);

        @Subscribe
        @AllowConcurrentEvents
        void listenString(String string);
    }
}

eventBus在register方法时会去加载带有@Subscribe的方法到loadingCache。又由于jvm的类加载机制,子类的方法会优先被遍历,导致带有@Subscribe的子类方法会取代父类方法加载到loadingCache,使父类方法上的@AllowConcurrentEvents注解无效。具体eventBus是怎么遍历,请看代码:

private static ImmutableList<Method> getAnnotatedMethodsInternal(Class<?> clazz) {
    Set<? extends Class<?>> supers = TypeToken.of(clazz).getTypes().rawTypes();
    Map<MethodIdentifier, Method> identifiers = Maps.newHashMap();
    //向上遍历所有相关的注册类,
    // (class eh.EventBusTest$EventListener1)->(interface eh.EventBusTest$EventListener)->(class java.lang.Object)
    for (Class<?> superClazz : supers) {
      for (Method superClazzMethod : superClazz.getMethods()) {
        if (superClazzMethod.isAnnotationPresent(Subscribe.class)
            && !superClazzMethod.isBridge()) {//桥接方法适用与泛型方法的override
          Class<?>[] parameterTypes = superClazzMethod.getParameterTypes();
          if (parameterTypes.length != 1) {
            throw new IllegalArgumentException("Method " + superClazzMethod
                + " has @Subscribe annotation, but requires " + parameterTypes.length
                + " arguments.  Event subscriber methods must require a single argument.");
          }

          MethodIdentifier ident = new MethodIdentifier(superClazzMethod);
          if (!identifiers.containsKey(ident)) {//用方法名和参数类型做判断
            identifiers.put(ident, superClazzMethod);
          }
        }
      }
    }
    return ImmutableList.copyOf(identifiers.values());
  }

推荐

@AllowConcurrentEvents@Subscribe一同使用

上一篇下一篇

猜你喜欢

热点阅读