就tm你叫EventBus啊?

292 阅读4分钟

前段时间,公司大佬的代码里出现了一个新面孔,名字叫做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啊”?