引入
上一篇文章EventBus基本使用中讲述了EventBus使用的三个步骤
- 第一步定义事件
public class MessageEvent {
public final String message;
public MessageEvent(String message) {
this.message = message;
}
}
- 第二步准备观察者和订阅方法
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
// This method will be called when a MessageEvent is posted (in the UI thread for Toast)
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}
// This method will be called when a SomeOtherEvent is posted
@Subscribe
public void handleSomethingElse(SomeOtherEvent event) {
doSomethingWith(event);
}
- 第三步发送事件
EventBus.getDefault().post(new MessageEvent("Hello everyone!"));
如果你还不清楚EventBus的使用,请参考我的上一篇文章EventBus基本使用与进阶配置下面我们就从这个三个步骤,切入到源码中,分析EventBus的实现原理,这里笔者分析的是EventBus3.x版本的。
源码分析
- EventBus.getDefault().register(Object subscriber)
// 注册主要做两件事 1.查找订阅者的所有订阅方法,2.将每个订阅方法与订阅者进行绑定(Subscription对象)
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
// 查找订阅者订阅方法的核心实现 通过反射/编译时注解生成的订阅信息
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 {
// 从注解处理器生成的订阅信息Index中查找,找不到内部还是通过反射继续查找
subscriberMethods = findUsingInfo(subscriberClass);
}
// 没有找到订阅方法,抛出异常!!!
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
// 加入缓存
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
上面的代码分析可以看出查找订阅方法是通过 findUsingInfo/findUsingReflection ,findUsingInfo是EventBus3.0之后一个优化点,之前EventBus版本获取订阅者方法是通过反射获取,而反射是运行时解析注解信息消耗性能。而现在一些主流的框架例如(ButterKnife等)开始在编译时解析注解信息(采用注解处理器),这样大大提升了运行时性能。
// 在注解处理器生成的Index中进行订阅方法查找
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
// FindState,把它理解为一个临时对象,主要是用来保存每次查找的订阅信息的。
// 其次FindState,作者使用了一种享元的设计模式,优化可性能,因为register其实是频繁调用的
// 这样会创建大量的FindState临时对象,通过这种设计实现复用,每次用完回收到对象池中。有兴趣
// 可以自己深入源码研究研究,这里暂时不分析它了。
FindState findState = prepareFindState();
findState.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 {
// 这里可以看到,如果在注解处理器生成的Index订阅信息中没找到,继续反射查找
findUsingReflectionInSingleClass(findState);
}
// 移动至父类查找
findState.moveToSuperclass();
}
// 返回查找到的所有订阅方法,并且回收FindState对象
return getMethodsAndRelease(findState);
}
// 将订阅者的每个订阅方法与订阅者进行绑定,生成订阅关系Subscription
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
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();
// 这个有个排序操作,相同事件,优先级高的订阅者排在优先级低的订阅者前面
// 注意这个在相同threadMode有效
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
// 保存订阅者的所有订阅事件Class
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
// 处理粘性事件,这里可以看到粘性事件的处理是regsiter中的。
// 粘性事件就是发送后,保存在内存中,之后订阅的时候,检测到订阅者有订阅粘性事件
// 则回调其订阅方法,订阅事件的处理下面分析
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);
}
}
}
// 反射查找订阅方法
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
try {
methods = findState.clazz.getMethods();
} catch (LinkageError error) {
// ...some log info ignore
throw new EventBusException(msg, error);
}
findState.skipSuperClasses = true;
}
for (Method method : methods) {
int modifiers = method.getModifiers();
// public 修饰的,非abstract 非static
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class<?>[] parameterTypes = method.getParameterTypes();
// 只有一个方法参数
if (parameterTypes.length == 1) {
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
// 含有@Subscibe注解
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)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException("@Subscribe method " + methodName +
"must have exactly 1 parameter but has " + parameterTypes.length);
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException(methodName +
" is a illegal @Subscribe method: must be public, non-static, and non-abstract");
}
}
}
register流程就看完了,通过register流程,我们将订阅信息保存到了两个map中。
// 事件类型为key,订阅关系列表为value的map。Subscription=【subscriber,subscriberMethod;】
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
// 订阅者为key,订阅的事件类型列表为vlaue的map。
private final Map<Object, List<Class<?>>> typesBySubscriber;
// 订阅关系封装
final class Subscription {
// 订阅者
final Object subscriber;
// 订阅方法
final SubscriberMethod subscriberMethod;
...
}
// 订阅方法封装
public class SubscriberMethod {
final Method method;//方法
final ThreadMode threadMode;//线程模式
final Class<?> eventType;//事件类型
final int priority;//优先级
final boolean sticky;//是否是粘性事件
...
}
- EventBus.getDefault().unregister(Object subscriber)
// 解除注册,主要是移除所有该订阅者关联的订阅关系
public synchronized void unregister(Object subscriber) {
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
// 移除subscriptionsByEventType中该订阅者相关的订阅关系
unsubscribeByEventType(subscriber, eventType);
}
// 移除typesBySubscriber中的订阅关系
typesBySubscriber.remove(subscriber);
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
// 移除subscriptionsByEventType中的所有该订阅者关联的订阅关系
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions != null) {
int size = subscriptions.size();
for (int i = 0; i < size; i++) {
Subscription subscription = subscriptions.get(i);
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}
- EventBus.getDefault().post(Object event)
// 发送事件
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;
}
}
}
// 封装事件发送的一些状态信息
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<>();//事件队列
boolean isPosting;//是否正在发送
boolean isMainThread;//是否是主线程
Subscription subscription;//订阅关系
Object event;//事件
boolean canceled;//是否取消了
}
// 发送事件
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
// 该属性控制是否查找事件的父类/父接口
// 意思是比如 AEvent extends BEvent implements CEvent
// 则最终会查找到三个事件 AEvent BEvent CEvent,然后遍历发送这三个事件
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);
}
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
// 发送单个事件
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
// 找到该事件对应的订阅关系
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted;
try {
// 回调订阅方法
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
// 如果事件被终止了,则结束剩余事件的发送
// POSTING模式可以在订阅方法中进行事件取消
if (aborted) {
break;
}
}
return true;
}
return false;
}
// 回调订阅方法,根据不同的线程模式,执行不同的调用策略,下面具体分析这几种线程模式实现
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
// POSTING模式
case POSTING:
invokeSubscriber(subscription, event);
break;
case MAIN:
// MAIN模式
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
// MAIN_ORDERED模式
case MAIN_ORDERED:
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
// BACKGROUND模式
case BACKGROUND:
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
// ASYNC模式
case ASYNC:
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
// 兜兜转转 最终是反射调用了目标订阅方法
void invokeSubscriber(Subscription subscription, Object event) {
try {
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unexpected exception", e);
}
}
EventBus.getDefault().postSticky(Object event)
// 发送粘性事件
public void postSticky(Object event) {
synchronized (stickyEvents) {
// 保存下来,这里是Map,相同类型的粘性事件会覆盖,订阅者将会收到最近最新的粘性事件
stickyEvents.put(event.getClass(), event);
}
// 发送事件 post流程之前已经说过
post(event);
}
三种Poster实现
-
HandlerPoster(事件需要在队列中排队执行)
public class HandlerPoster extends Handler implements Poster { // 存放执行的PostEvents 的事件队列 private final PendingPostQueue queue; // Post 事件在handleMessage 中执行的最大时间值 private final int maxMillisInsideHandleMessage; private final EventBus eventBus; // 标识Handler是否是运行的 private boolean handlerActive; protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) { super(looper); this.eventBus = eventBus; this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage; queue = new PendingPostQueue(); } public void enqueue(Subscription subscription, Object event) { PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event); synchronized (this) { queue.enqueue(pendingPost); // enqueue后,将这个poster运行起来,sendMessage,然后回到handleMessage中处理 // 之后每次事件存储在队列中,handleMessage则不断循环队列保存的事件进行处理调用 if (!handlerActive) { handlerActive = true; if (!sendMessage(obtainMessage())) { throw new EventBusException("Could not send handler message"); } } } } @Override public void handleMessage(Message msg) { boolean rescheduled = false; try { long started = SystemClock.uptimeMillis(); while (true) { PendingPost pendingPost = queue.poll(); if (pendingPost == null) { synchronized (this) { // Check again, this time in synchronized pendingPost = queue.poll(); if (pendingPost == null) { handlerActive = false; return; } } } // 回调订阅方法 eventBus.invokeSubscriber(pendingPost); long timeInMethod = SystemClock.uptimeMillis() - started; if (timeInMethod >= maxMillisInsideHandleMessage) { // 单个事件处理事件过长,重新sendMessage,剩下的事件在另一个message中处理 if (!sendMessage(obtainMessage())) { throw new EventBusException("Could not send handler message"); } rescheduled = true; return; } } } finally { handlerActive = rescheduled; } } }
-
BackgroundPoster(事件需要在线程池的单个线程中排队执行)
final class BackgroundPoster implements Runnable, Poster { // 事件队列 private final PendingPostQueue queue; private final EventBus eventBus; private volatile boolean executorRunning; BackgroundPoster(EventBus eventBus) { this.eventBus = eventBus; queue = new PendingPostQueue(); } public void enqueue(Subscription subscription, Object event) { PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event); synchronized (this) { // enqueue之后,将这个poster运行起来 // 之后run方法中不断从队列中取出事件执行 queue.enqueue(pendingPost); if (!executorRunning) { executorRunning = true; // 这里是Executors.newCachedThreadPool( eventBus.getExecutorService().execute(this); } } } @Override public void run() { try { try { while (true) { PendingPost pendingPost = queue.poll(1000); if (pendingPost == null) { synchronized (this) { // Check again, this time in synchronized pendingPost = queue.poll(); if (pendingPost == null) { executorRunning = false; return; } } } // 回调订阅方法 eventBus.invokeSubscriber(pendingPost); } } catch (InterruptedException e) { eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e); } } finally { executorRunning = false; } } }
-
AsyncPoster(事件不需要排队,直接在线程池中执行)
class AsyncPoster implements Runnable, Poster { // 事件队列 private final PendingPostQueue queue; private final EventBus eventBus; AsyncPoster(EventBus eventBus) { this.eventBus = eventBus; queue = new PendingPostQueue(); } // 事件一入队列,就放到线程池执行,不用排队,达到快速响应 public void enqueue(Subscription subscription, Object event) { PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event); queue.enqueue(pendingPost); eventBus.getExecutorService().execute(this); } @Override public void run() { PendingPost pendingPost = queue.poll(); if(pendingPost == null) { throw new IllegalStateException("No pending post available"); } // 回调订阅方法 eventBus.invokeSubscriber(pendingPost); } }
总结
EventBus设计亮点
-
Builder设计模式,实现对象的自定义配置,灵活性很高
EventBus参数的配置项实际上是通过EventBusBuildr配置的,通过我们调用getDefault()方式是通过一个默认的EventBusBuillder配置项获取EventBus实例。这样设计的好处便于拓展,通过EventBusBuilder你可以拓展自己的其他配置,而针对普通用户不需要拓展的通过一个默认配置项配置获取。这种设计方式可以应用到我们设计组件的时候,如果我们对外暴露的接口可以传入很多配置项的,这时候我们可以考虑这种设计,一般用户我们采用一个默认的配置。
-
享元设计模式,比如FindState的对象池设计,PendingPost对象池设计,避免了大量临时对象的创建。实现了对象复用
EventBus内部register/unregister,是会被频繁调用的,FindState是对register查找过程中生成的订阅信息的封装。那么每次会产生大量的临时对象,所以内部对象池的设计优化了内存使用,避免大量对象的创建。PendingPost也是同理,它是对post分发事件的封装,也是采用了对象池设计。
-
策略模式,比如内部多种线程模式的支持,通过封装不同模式的策略,更加的解耦,灵活替换
EventBus内部支持多种线程模式,通过策略模式设计,将不同的线程模式封装成Poster,更加的解耦,灵活替换。
-
生产者消费者模式设计思想,比如内部支持线程模式的Poster的实现,通过Consumer-Producer实现事件的分发
EventBus内部线程模式的实现Poster,内部通过单链表的形式封装了一个消息队列,事件在队列中进行传递消费。
-
ThreadLocal设计,每个发布线程维护自身的一个发布状态信息,使用ThreadLocal实现程隔离,相对于使用同步锁实现线程安全,速度更快。
-
EventBus3.x的优化,引入了注解处理器,编译时生成相关的订阅信息,替代了运行反射查找订阅方法对性能的消耗,优化了运行时性能。
思考感悟
- 通过阅读EventBus源码,可以看出作者很多地方的精彩设计,很值得我们学习,在我们平时写代码的过程中,学会运用这种思想。这样自己才会提升
- 任何优秀框架的设计都不是一遍两遍就能看明白的,要下功夫多看几遍,慢慢理解到作者的设计思路。这样才能便于我们理解整个源码
- 举例阅读EventBus源码,我们首先抓住它的核心功能,是一个事件的订阅-发布系统,核心是观察者设计模式,如果让我们简单来设计这样一个组件通信,我们会怎么做,带着这种思路去看作者的思路,会更利于我们理解源码。