EventBus : 事件总线
-
EventBus 是Guava的事件处理机制,是观察者模式的优雅实现。
-
使用Guava中的EventBus时,不需要再实现指定接口,只需要在指定的方法上实现@Subscribe注解即可。
-
小栗子:
public class EventListener { //订阅者
//@Subscribe保证有且只有一个输入参数,如果你需要订阅某种类型的消息,只需要在指定的方法上加上 @Subscribe注解即可
@Subscribe
public void listen(OrderEvent event){
System.out.println("receive message: "+event.getMessage());
}
/*
一个subscriber也可以同时订阅多个事件
Guava会通过事件类型来和订阅方法的形参来决定到底调用subscriber的哪个订阅方法
*/
@Subscribe
public void listen(String message){
System.out.println("receive message: "+message);
}
}
public class MultiEventListener { //订阅者
@Subscribe
public void listen(OrderEvent event){
System.out.println("MultiEventListener receive msg: "+event.getMessage());
}
@Subscribe
public void listen(String message){
System.out.println("MultiEventListener receive msg: "+message);
}
}
//发布-订阅模式中传递的事件,是一个普通的POJO类
public class OrderEvent {
private String message;
public OrderEvent(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
//测试方法
public static void main(String[] args) {
EventBus eventBus = new EventBus("jack");
/*
如果多个subscriber订阅了同一个事件,那么每个subscriber都将收到事件通知
并且收到事件通知的顺序跟注册的顺序保持一致
*/
eventBus.register(new EventListener()); //注册订阅者
eventBus.register(new MultiEventListener());
eventBus.post(new OrderEvent("hello")); //发布事件
eventBus.post(new OrderEvent("world"));
eventBus.post("!");
//out
/**
* receive message: hello
* MultiEventListener receive msg: hello
* receive message: world
* MultiEventListener receive msg: world
* receive message: !
* MultiEventListener receive msg: !
**/
}
}
EventBus 观察
-
EventBus中的订阅者们和注册方法
private final SubscriberRegistry subscribers;
public void register(Object object) {
this.subscribers.register(object);
}
void register(Object listener) {
Multimap<Class<?>, Subscriber> listenerMethods = this.findAllSubscribers(listener);
...
}
- 注册时会找到 listener 中所有带有 @Subscribe 的方法,并根据方法的参数类型进行分类
private Multimap<Class<?>, Subscriber> findAllSubscribers(Object listener) {
Multimap<Class<?>, Subscriber> methodsInListener = HashMultimap.create();
Class<?> clazz = listener.getClass();
Iterator i$ = getAnnotatedMethods(clazz).iterator();
while(i$.hasNext()) {
Method method = (Method)i$.next();
Class<?>[] parameterTypes = method.getParameterTypes();
Class<?> eventType = parameterTypes[0];
methodsInListener.put(eventType, Subscriber.create(this.bus, listener, method));
}
return methodsInListener;
}
- 判断方法是不是订阅者
private static ImmutableList<Method> getAnnotatedMethodsNotCached(Class<?> clazz) {
Set<? extends Class<?>> supertypes = TypeToken.of(clazz).getTypes().rawTypes();
Map<SubscriberRegistry.MethodIdentifier, Method> identifiers = Maps.newHashMap();
Iterator i$ = supertypes.iterator();
while(i$.hasNext()) {
Class<?> supertype = (Class)i$.next();
Method[] arr$ = supertype.getDeclaredMethods();
int len$ = arr$.length;
for(int i$ = 0; i$ < len$; ++i$) {
Method method = arr$[i$];
if (method.isAnnotationPresent(Subscribe.class) && !method.isSynthetic()) {
...
}
}
}
return ImmutableList.copyOf(identifiers.values());
}
- 通知方法 , 获取参数为event类型的全部观察者
public void post(Object event) {
Iterator<Subscriber> eventSubscribers = this.subscribers.getSubscribers(event);
if (eventSubscribers.hasNext()) {
this.dispatcher.dispatch(event, eventSubscribers);
} else if (!(event instanceof DeadEvent)) {
this.post(new DeadEvent(this, event));
}
}
- 将通知分发给观察者们
void dispatch(Object event, Iterator<Subscriber> subscribers) {
Preconditions.checkNotNull(event);
Preconditions.checkNotNull(subscribers);
Queue<Dispatcher.PerThreadQueuedDispatcher.Event> queueForThread = (Queue)this.queue.get();
queueForThread.offer(new Dispatcher.PerThreadQueuedDispatcher.Event(event, subscribers));
if (!((Boolean)this.dispatching.get()).booleanValue()) {
this.dispatching.set(true);
Dispatcher.PerThreadQueuedDispatcher.Event nextEvent;
try {
while((nextEvent = (Dispatcher.PerThreadQueuedDispatcher.Event)queueForThread.poll()) != null) {
while(nextEvent.subscribers.hasNext()) {
((Subscriber)nextEvent.subscribers.next()).dispatchEvent(nextEvent.event);
}
}
} finally {
this.dispatching.remove();
this.queue.remove();
}
}
}
- 具体的执行带有 @Subscribe 的方法,异步执行,提高效率
final void dispatchEvent(final Object event) {
this.executor.execute(new Runnable() {
public void run() {
try {
Subscriber.this.invokeSubscriberMethod(event);
} catch (InvocationTargetException var2) {
Subscriber.this.bus.handleSubscriberException(var2.getCause(), Subscriber.this.context(event));
}
}
});
}