jadestoner

导航

 

简单使用

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处理任务。

拓展

1.基于spring的消息总线

2..基于spring,rabbitmq的分布式消息总线

posted on 2021-03-15 16:00  jadestoner  阅读(168)  评论(0编辑  收藏  举报