简单使用
0.引入
compile 'com.google.guava:guava:19.0'
1.初始化
EventBus bus = new EventBus();
2.定义一个事件监听者
任何一个方法上加上注解 @Subscribe 即可
// 定义消息体
public class HelloEvent{
}
// 定义消息监听器
public class HelloListener{
@Subscribe
public void listen1(HelloEvent event){
System.out.println("received event = " + event);
}
}
3. 将listener注册到eventbus对象
HelloListener listener = new HelloListener();
bus.register(listener);
4.生产端发送消息
HelloEvent event = new HelloEvent();
bus.post(event);
// 全部结束,此时,listener会自动接收到消息,执行打印日志操作
名词概念及源码实现
eventbus的核心类非常少,逻辑也简单,简单记录一下
EventBus
EventBus有以下几个主要的属性
// 名字
private final String identifier;
// 任务执行器,这是jdk中类,非eventbus提出的名词
private final Executor executor;
// listener统一的异常处理器
private final SubscriberExceptionHandler exceptionHandler;
// 订阅者注册中心
private final SubscriberRegistry subscribers = new SubscriberRegistry(this);
// 消息分发器
private final Dispatcher dispatcher;
new 操作
当你 new 一个 Eventbus 对象的时候(指使用无参构造函数new EventBus()),会设置的默认值如下
this.subscribers = new SubscriberRegistry(this);
this.identifier = "default";
this.executor = MoreExecutors.directExecutor();
this.dispatcher = Dispatcher.perThreadDispatchQueue(),
this.exceptionHandler = LoggingHandler.INSTANCE
这些对象表示的意义后面会说明。
register 操作
bus.register(listener);
public void register(Object object) {
subscribers.register(object);
}
events 将register的逻辑移交给了subscribers。
SubscriberRegistry类的register方法如下
void register(Object listener) {
// 1.遍历所有的方法,找出标注了@Subscribe注解的方法;
// 2.将方法包装成一个个的Subscriber对象;
// 3. listenerMethods的key是消息的类型,value是Subscriber对象列表
Multimap<Class<?>, Subscriber> listenerMethods = findAllSubscribers(listener);
for (Entry<Class<?>, Collection<Subscriber>> entry : listenerMethods.asMap().entrySet()) {
Class<?> eventType = entry.getKey();
Collection<Subscriber> eventMethodsInListener = entry.getValue();
CopyOnWriteArraySet<Subscriber> eventSubscribers = subscribers.get(eventType);
// 将本方法中的Subscriber加到注册中心。
// 至此,就完成了listener的注册功能
if (eventSubscribers == null) {
CopyOnWriteArraySet<Subscriber> newSet = new CopyOnWriteArraySet<>();
eventSubscribers =
MoreObjects.firstNonNull(subscribers.putIfAbsent(eventType, newSet), newSet);
}
eventSubscribers.addAll(eventMethodsInListener);
}
}
与register方法对应的还有一个unregister方法,基本用不到,不在赘述。
post 操作
// 从注册中心中找出此消息的全部Subscriber
public void post(Object event) {
Iterator<Subscriber> eventSubscribers = subscribers.getSubscribers(event);
if (eventSubscribers.hasNext()) {
// 消息分发器 实现 将消息投递到相应Subscriber的功能。
dispatcher.dispatch(event, eventSubscribers);
} else if (!(event instanceof DeadEvent)) {
// the event had no subscribers and was not itself a DeadEvent
post(new DeadEvent(this, event));
}
}
SubscriberRegistry
Dispatcher
抽象类,只有一个抽象方法,实现如何将event分发给相应的subscribers
abstract void dispatch(Object event, Iterator<Subscriber> subscribers);
默认提供了三种Dispatcher,分别为:
static Dispatcher perThreadDispatchQueue() {
return new PerThreadQueuedDispatcher();
}
static Dispatcher legacyAsync() {
return new LegacyAsyncDispatcher();
}
static Dispatcher immediate() {
return ImmediateDispatcher.INSTANCE;
}
分别介绍一下:
1.PerThreadQueuedDispatcher
同步的eventbus,默认使用了PerThreadQueuedDispatcher作为它的dispatcher
源码如下:
private static final class PerThreadQueuedDispatcher extends Dispatcher {
private final ThreadLocal<Queue<Event>> queue =
new ThreadLocal<Queue<Event>>() {
@Override
protected Queue<Event> initialValue() {
return Queues.newArrayDeque();
}
};
private final ThreadLocal<Boolean> dispatching =
new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return false;
}
};
@Override
void dispatch(Object event, Iterator<Subscriber> subscribers) {
Queue<Event> queueForThread = queue.get();
queueForThread.offer(new Event(event, subscribers));
if (!dispatching.get()) {
dispatching.set(true);
try {
Event nextEvent;
//
// 笔者很疑惑,这里为啥要用while循环,
//
while ((nextEvent = queueForThread.poll()) != null) {
while (nextEvent.subscribers.hasNext()) {
nextEvent.subscribers.next().dispatchEvent(nextEvent.event);
}
}
} finally {
dispatching.remove();
queue.remove();
}
}
}
private static final class Event {
private final Object event;
private final Iterator<Subscriber> subscribers;
private Event(Object event, Iterator<Subscriber> subscribers) {
this.event = event;
this.subscribers = subscribers;
}
}
}
2.LegacyAsyncDispatcher
异步eventbus,默认使用LegacyAsyncDispatcher作为分发器。
因为queue这个对象是个全局变量,而步骤1和步骤2并没有用锁锁住,
当有多个线程同时调用dispatch方法时,
就会出现,线程a发出了一个事件a,结果被线程b处理了,而自己处理了线程b发出的事件a。
private static final class LegacyAsyncDispatcher extends Dispatcher {
private final ConcurrentLinkedQueue<EventWithSubscriber> queue =
Queues.newConcurrentLinkedQueue();
@Override
void dispatch(Object event, Iterator<Subscriber> subscribers) {
checkNotNull(event);
// 步骤1
while (subscribers.hasNext()) {
queue.add(new EventWithSubscriber(event, subscribers.next()));
}
// // 步骤2
EventWithSubscriber e;
while ((e = queue.poll()) != null) {
e.subscriber.dispatchEvent(e.event);
}
}
private static final class EventWithSubscriber {
private final Object event;
private final Subscriber subscriber;
private EventWithSubscriber(Object event, Subscriber subscriber) {
this.event = event;
this.subscriber = subscriber;
}
}
}
3.ImmediateDispatcher
这个类,很简单,在当前线程内完成了disoatchEvent操作。
笔者有点搞不清,它和PerThreadQueuedDispatcher的区别在哪。
private static final class ImmediateDispatcher extends Dispatcher {
private static final ImmediateDispatcher INSTANCE = new ImmediateDispatcher();
@Override
void dispatch(Object event, Iterator<Subscriber> subscribers) {
checkNotNull(event);
while (subscribers.hasNext()) {
subscribers.next().dispatchEvent(event);
}
}
}
SubscriberExceptionHandler
eventbus的全局异常处理器,
当Subscriber 处理消息出现异常时,就会调用,详细信息参考 Subscriber
public interface SubscriberExceptionHandler {
void handleException(Throwable exception, SubscriberExceptionContext context);
}
默认是个log
static final class LoggingHandler implements SubscriberExceptionHandler {
static final LoggingHandler INSTANCE = new LoggingHandler();
@Override
public void handleException(Throwable exception, SubscriberExceptionContext context) {
Logger logger = logger(context);
if (logger.isLoggable(Level.SEVERE)) {
logger.log(Level.SEVERE, message(context), exception);
}
}
Subscriber
eventbus.register(listener)的时候会遍历出所有标注了@SubScribe的方法,组装成Subscriber对象。
Dispatcher分发消息的时候会直接调用Subscriber对象的dispatchEvent方法,该方法内会将反射调用方法的逻辑放在一个Runnable里,
由executor来决定怎么执行任务里,是同步还是异步。
private Subscriber(EventBus bus, Object target, Method method) {
this.bus = bus;
this.target = checkNotNull(target);
this.method = method;
method.setAccessible(true);
this.executor = bus.executor();
}
/** Dispatches {@code event} to this subscriber using the proper executor. */
final void dispatchEvent(final Object event) {
executor.execute(
new Runnable() {
@Override
public void run() {
try {
method.invoke(target, checkNotNull(event));
} catch (InvocationTargetException e) {
// 当方法调用失败,就会统一调用SubscriberExceptionHandler处理异常
bus.handleSubscriberException(e.getCause(), context(event));
}
}
});
}
Executor
同jdk中的Executor
原理
eventbus是根据发布订阅模式来设计的。
这里要解释下 【发布订阅模式】和【观察者模式】的区别:可以参阅这边文章 https://www.cnblogs.com/lovesong/p/5272752.html
eventbus register listener的时候 遍历出所有标注了@SubScribe的方法,组装成Subscriber对象;
eventbus post object的时候 会根据object的类型选择相对应的Subscriber,根据配置的Executor处理任务。