Excellent open-source code analysis (a) Google guava of EventBus

Java Geeks | Author /   Kengran leaf
This is a Java geeks of 49 original articles

1, open source learning gains

Learning open source can have the following benefits:

1. learn some of its architectural design, take a look at how to implement a highly available, scalable architecture.

2. Learn some good java syntax, after all, you will not be using all of the java syntax in actual code process, and in the process look at the source code, there are likely to find that you have not used before, but more clever usage.

3. Learn design patterns, open source often use some design patterns can deepen your understanding of design patterns.

4. learn some basic design principles, such as by bounded queue to avoid memory overflow, improve performance by the asynchronous thread, by improving scalability dependency injection, testability and the like.

2. What is EventBus

EventBus Google is an open source library that uses a publish / subscribe model to those who decouple the project. It can use very little code to implement communication between multiple components.

3, EventBus code structure

EventBus code structure is as follows:

Class Description:


EventBus entrance is the core class, if all the default implementation, only need to implement Listener, and all functions can be completed by EventBus class method call.


SubscriberExceptionHandler abnormal processing interface, replaceable own implementation.


Executor Listener listens for asynchronous execution method, alternative own implementation.


Dispatcher is the event dispatch interface that can replace your own implementation, provides three default implementation class.


SubscriberRegistry class event registration is also used to get subscribers.


Subscriber is a subscriber, to do Listener package, shielding the complexity of call logic, so that the user does not have to care about these complex logic, as long as you can provide specific Listener implementation.


SynchronizedSubscriber is subscriber support concurrent calls, by adding AllowConcurrentEvents comment on the event listener method Listener to achieve the purpose of use SynchronizedSubscriber.


Subscribe is an annotation class, you can add annotations to the expression of this method is an event listener method on any class method.


DeadEvent used to record events that have no subscribers.


SubscriberExceptionContext abnormal context for context information related to the recording when the subscriber exception handling, exception handling easy implementation class to obtain the information to handle the exception.

4, EventBus outstanding between

1. Oriented Programming Interface: Executor, Dispatcher, SubscriberExceptionHandler are interfaces, a user can replace a specific category.

2. Use dependency injection, so that testability enhancement. Can be seen from FIG EventBus hold Executor, Dispatcher, SubscriberExceptionHandler three objects, which can be injected through EventBus constructor, so users have the opportunity to easily replace the specific implementation, or a mock object for testing. If they are not injectable, but within a certain method calls directly, you lose the opportunity to replace. Of course, there are many ways interface injection, for example by the method set, dynamically generated by reflection, etc., but the configuration is the easiest, most worry the injection method.

3. asynchronous processing and improve performance. Subscriber final event processing is executed in an asynchronous thread way through Executor, it will not be synchronized blocked, greatly improving performance.

4. Use + Subscribe annotations reflection, such that any class of any method can be an event listener class without having to implement specific listener interface.

5. Consider the exception handling mechanism, on the one hand provides SubscriberExceptionHandler interface to allow users to achieve specific processing logic, on the other hand provides DeadEvent categories, those events would lose subscribers to DeadEvent unified classification, implemented by the users themselves a Listener to deal with them.

6. curing the entire call flow through the template method, users need only a simple implementation can be used as required.

5, EventBus specific use

5.1, to achieve a Listener

5.1.1 Instructions

Listener is an event listener class, a class Listener can listen to multiple events simultaneously in different ways, any class can be used as Listener, but need to follow the following requirements:

1. Subscribe must add annotations on listener method is a method for the expression of the listener method

2. This method can only monitor a parameter, this parameter is the event to listen, parameters can be understood as class Class is to listen EventType

5.1.2, the relevant code

1.Listener examples

public class MyListener {

  // 添加Subscribe注解则表示要监听某个事件
  public void onEvent(MyEvent1 event1) {
    // do something
  // 一个Listener可以监听多个事件
  public void onEvent(MyEvent2 event2) {
    // do something


  // 传入的clazz类就是Listener的Class
  private static ImmutableList<Method> getAnnotatedMethodsNotCached(Class<?> clazz) {
    Set<? extends Class<?>> supertypes = TypeToken.of(clazz).getTypes().rawTypes();
    Map<MethodIdentifier, Method> identifiers = Maps.newHashMap();
    for (Class<?> supertype : supertypes) {
      for (Method method : supertype.getDeclaredMethods()) {
        // 这里查找方法上是否有Subscribe注解
        if (method.isAnnotationPresent(Subscribe.class) && !method.isSynthetic()) {
          // TODO(cgdecker): Should check for a generic parameter type and error out
          Class<?>[] parameterTypes = method.getParameterTypes();
          // 这里检查方法的参数只有1个
              parameterTypes.length == 1,
              "Method %s has @Subscribe annotation but has %s parameters."
                  + "Subscriber methods must have exactly 1 parameter.",

          MethodIdentifier ident = new MethodIdentifier(method);
          if (!identifiers.containsKey(ident)) {
            identifiers.put(ident, method);
    return ImmutableList.copyOf(identifiers.values());

5.2, construction EventBus

5.2.1 Instructions

1. In a system, according to different purposes, there may be multiple simultaneous EventBus, different EventBus identified by identifier.

2. To facilitate use, a plurality of constructors EventBus provided, the user can inject different implementation class required, the most simple structure is a constructor with no arguments, all use the default implementation.

3. In actual use, the class may be used to hold a single embodiment EventBus instance, if necessary, can hold different EventBus examples of different purposes.

5.2.2, the relevant code


  public EventBus() {
  public EventBus(String identifier) {
  public EventBus(SubscriberExceptionHandler exceptionHandler) {
      String identifier,
      Executor executor,
      Dispatcher dispatcher,
      SubscriberExceptionHandler exceptionHandler) {
    this.identifier = checkNotNull(identifier);
    this.executor = checkNotNull(executor);
    this.dispatcher = checkNotNull(dispatcher);
    this.exceptionHandler = checkNotNull(exceptionHandler);

5.3, registered Listener

5.3.1 Instructions

After the above two steps, you can register Listener by EventBus.

5.3.2, the relevant code


  private final SubscriberRegistry subscribers = new SubscriberRegistry(this);
  public void register(Object object) {


  void register(Object listener) {
    // 查找有Subscribe注解的方法,并封装为Subscriber,Multimap的key记录的Class就是要监听的对象的Class
    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);


5.4, ​​released Event

5.4.1 Instructions

Publishing events is relatively simple, as long as the need to publish local events to get EventBus instance, you can then call the post method.

5.4.2, the relevant code


  public void post(Object event) {
    // 根据event找到订阅者,这里实际是根据event.Class来查找,也即和Listener的监听方法的参数的Class一致。
    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));


  final void dispatchEvent(final Object event) {
    // 通过executor来实现异步调用,这个executor在EventBus是可注入的,可以注入修改后的实现类
        new Runnable() {
          public void run() {
            try {
            } catch (InvocationTargetException e) {
              // 这里最终调用的是在EventBus中注入的SubscriberExceptionHandler,可以注入修改后的实现类
              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;

6, Google guava source address



Java Geek site: javageektour.com/

Guess you like

Origin juejin.im/post/5e770e98e51d452701798a77