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
一同使用