前段时间,公司大佬的代码里出现了一个新面孔,名字叫做EventBus???这是什么玩意儿?赶紧去百度一下:
- 传统上,Java的进程内事件分发都是通过发布者和订阅者之间的显式注册实现的。
- 设计EventBus就是为了取代这种显示注册方式,使组件间有了更好的解耦。
- EventBus不是通用型的发布-订阅实现,不适用于进程间通信。
原来是取代事件分发的发布订阅模式啊!那到底是怎么实现的呢?大佬的想法我想像不到啊!赶紧去问问:
菜鸟kk:大佬,我看你在项目中用了EventBus,能给我讲讲原理吗?
大佬:你知道观察者模式吗?
菜鸟kk:不知道...
大佬:赶紧去看看吧,看了你就懂了。
看完观察者模式,脑子里弹出个想法:“就这?“,路过的大佬好像看出了我的疑惑,叮嘱到:
大佬:看完观察者模式了吧?
菜鸟kk:嗯!看完了!
大佬:那就自己动手写一个demo,实践是检验真理的唯一标准!
菜鸟kk:好的!我这就去!
首先创建一个EventBus实例发布事件event,针对不同的实例,使用post方法来通知监听者接收信息:
public class Test {
public static void main(String[] args) {
EventBus eventBus = new EventBus();
eventBus.register(new Subscriber());
eventBus.post(new Event1("测试个锤子"));
eventBus.post(new Event2("测试个果子"));
}
}
创建两个不同的实体类:
@Data
public class Event1 {
private String message;
public Event1(String message) {
this.message = message;
}
}
@Data
public class Event2 {
private String message;
public Event2(String message) {
this.message = message;
}
}
所有的监听者都必须用@Subscribe注解声明:
public class Subscriber {
@Subscribe
public void subscribe1(Event1 event1){
System.out.println("1st event" + event1.getMessage());
}
@Subscribe
public void subscribe2(Event2 event2){
System.out.println("2nd event" + event2.getMessage());
}
}
最终的执行结果为:
最终的执行结果为:
思想上达成了统一,但是在使用上真的就完全一致吗?抱着好奇的心态,再一次找到大佬:
菜鸟kk:大佬,我对比了观察者模式和EventBus的使用方法,好像有点不一样啊!
大佬:哦?哪里不一样呢?
菜鸟kk:你的使用方法好像不是通知给全部观察者啊?
大佬:确实存在一些不同,只有参数相同的情况下才可以通知的,还是看看源码吧!
大佬的操作和我们确实不一样,要看明白还是得看看源码,从根本处解决问题!让我们仔细研究研究:
/** Registers all subscriber methods on the given listener object. */
void register(Object listener) {
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);
if (eventSubscribers == null) {
CopyOnWriteArraySet<Subscriber> newSet = new CopyOnWriteArraySet<>();
eventSubscribers =
MoreObjects.firstNonNull(subscribers.putIfAbsent(eventType, newSet), newSet);
}
eventSubscribers.addAll(eventMethodsInListener);
}
}
首先是接收者注册方法;listenerMethods是一个一对多的Multimap,存放着多有的subscriber,进入方法findAllSubscribers中看看具体的实现是什么:
/**
* Returns all subscribers for the given listener grouped by the type of event they subscribe to.
*/
private Multimap<Class<?>, Subscriber> findAllSubscribers(Object listener) {
Multimap<Class<?>, Subscriber> methodsInListener = HashMultimap.create();
Class<?> clazz = listener.getClass();
for (Method method : getAnnotatedMethods(clazz)) {
Class<?>[] parameterTypes = method.getParameterTypes();
Class<?> eventType = parameterTypes[0];
methodsInListener.put(eventType, Subscriber.create(bus, listener, method));
}
return methodsInListener;
}
findAllSubscribers方法通过反射获取listener中所有使用了注解@Subscribe的方法,将这些方法按照首个参数(使用@Subscribe注解的方法只允许使用一个参数,Method public void com.test.bus.test.Subscriber.subscribe2(com.test.bus.test.event.Event2,java.lang.String) has @Subscribe annotation but has 2 parameters. Subscriber methods must have exactly 1 parameter.
)类型来分类,存储在一个Multimap中。然后就是EventBus通过post方法来通知接收者:
public void post(Object event) {
Iterator<Subscriber> eventSubscribers = subscribers.getSubscribers(event);
if (eventSubscribers.hasNext()) {
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));
}
}
通过subscribers.getSubscribers(event)
获取到event对应的所有Subscriber,然后使用dispatcher.dispatch(event, eventSubscribers)
来通知Subscriber执行对应的dispatch方法:
- ImmediateDispatcher(直接通知所有符合条件的接收者)
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);
}
}
}
- LegacyAsyncDispatcher(两个循环,一个进行将所有的event对象插入队列,另一个从队列中取出event发送给对应的接收者)
void dispatch(Object event, Iterator<Subscriber> subscribers) {
checkNotNull(event);
while (subscribers.hasNext()) {
queue.add(new EventWithSubscriber(event, subscribers.next()));
}
EventWithSubscriber e;
while ((e = queue.poll()) != null) {
e.subscriber.dispatchEvent(e.event);
}
}
- PerThreadQueuedDispatcher(两个线程私有的ThreadLocal对象,前者进行存储当前线程中的event对象,后者进行判断当前线程是否被占用)
/** Per-thread queue of events to dispatch. */
private final ThreadLocal<Queue<Event>> queue =
new ThreadLocal<Queue<Event>>() {
@Override
protected Queue<Event> initialValue() {
return Queues.newArrayDeque();
}
};
/** Per-thread dispatch state, used to avoid reentrant event dispatching. */
private final ThreadLocal<Boolean> dispatching =
new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return false;
}
};
void dispatch(Object event, Iterator<Subscriber> subscribers) {
checkNotNull(event);
checkNotNull(subscribers);
Queue<Event> queueForThread = queue.get();
queueForThread.offer(new Event(event, subscribers));
if (!dispatching.get()) {
dispatching.set(true);
try {
Event nextEvent;
while ((nextEvent = queueForThread.poll()) != null) {
while (nextEvent.subscribers.hasNext()) {
nextEvent.subscribers.next().dispatchEvent(nextEvent.event);
}
}
} finally {
dispatching.remove();
queue.remove();
}
}
}
dispatch方法一共有以上三种方式,具体的使用在构造函数EventBus中可以选择:
EventBus(
String identifier,
Executor executor,
Dispatcher dispatcher,
SubscriberExceptionHandler exceptionHandler) {
this.identifier = checkNotNull(identifier);
this.executor = checkNotNull(executor);
this.dispatcher = checkNotNull(dispatcher);
this.exceptionHandler = checkNotNull(exceptionHandler);
}
每一个event处理过程都是私有线程进行处理的,它的核心代码如下:
/** 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 {
invokeSubscriberMethod(event);
} catch (InvocationTargetException e) {
bus.handleSubscriberException(e.getCause(), context(event));
}
}
});
}
然后通过反射的方式执行方法:
void invokeSubscriberMethod(Object event) throws InvocationTargetException {
try {
method.invoke(target, checkNotNull(event));
} catch (IllegalArgumentException e) {
throw new Error("Method rejected target/argument: " + event, e);
} catch (IllegalAccessException e) {
throw new Error("Method became inaccessible: " + event, e);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof Error) {
throw (Error) e.getCause();
}
throw e;
}
}
终于看完了,虽然有好多细节和功能没有深入研究,但是至少浅显的了解了EventBus的基础原理,要想深入理解,还是要好好读源码!终于接触到了大佬的成长方法,要是一直坚持下去,以后我一定也可以对EventBus说:“就tm你叫EventBus啊”?