Java --- Guava Event Bus

Java --- Guava Event Bus

Event Bus其实就是发布者-订阅者模式,Guava EventBus提供了一个通用的Event Bus实现,通过注释和约定,将应用中的所有发布者和订阅者模式实现集中管理,而不用针对不同的事件实现不同的事件驱动。


图1 GuavaEvent 结构

 

简单使用实例

下面是一段使用EventBus的简单示例代码:

publicclass EventBusTest {

 

    publicstaticvoid main(String[] args) {

       EventBus eb = new EventBus("test");

      

       eb.register(new EventListener());

      

       eb.post(new EventA());

       eb.post(new EventB());

    }

 

    staticclass EventA{}

    staticclass EventB{}

    staticclass EventListener{

      

       @Subscribe

       publicvoid processEvent(EventA event){

           System.out.println("eventA happ");

       }

      

       @Subscribe

       publicvoid processEvent(EventB event){

           System.out.println("eventB happ");

       }

    }

}

 

EventBus使用涉及以下实体:

EventBus: 事件总线,提供订阅者的注册,事件的发布等方法。

Subscriber: 订阅者,可以是任何对象,只要在方法中添加@Subscribe注释,则可以作为一个订阅者。

Event: 事件,订阅者关注的事件,可以是任何对象,在订阅者的@Subscribe方法中的第一个参数为该订阅者订阅的对象类型。

 

使用流程如下:

1.      获取事件总线

2.      注册订阅者

3.      发布事件

 

事件的执行

下面是EventBus事件发布和订阅者方法调用的代码段:

  publicvoid post(Object event) {

    Set<Class<?>> dispatchTypes = flattenHierarchy(event.getClass());

 

    booleandispatched = false;

    for (Class<?> eventType : dispatchTypes) {

      subscribersByTypeLock.readLock().lock();

      try {

        Set<EventSubscriber> wrappers = subscribersByType.get(eventType);

 

        if (!wrappers.isEmpty()) {

          dispatched = true;

          for (EventSubscriber wrapper : wrappers) {

            enqueueEvent(event, wrapper);

          }

        }

      } finally {

        subscribersByTypeLock.readLock().unlock();

      }

    }

 

    if (!dispatched && !(eventinstanceof DeadEvent)) {

      post(new DeadEvent(this, event));

    }

 

    dispatchQueuedEvents();

  }

 

  void dispatchQueuedEvents() {

    // don't dispatch if we're already dispatching, that would allow reentrancy

    // and out-of-order events. Instead, leave the events to be dispatched

    // after the in-progress dispatch is complete.

    if (isDispatching.get()) {

      return;

    }

 

    isDispatching.set(true);

    try {

      Queue<EventWithSubscriber> events = eventsToDispatch.get();

      EventWithSubscriber eventWithSubscriber;

      while ((eventWithSubscriber = events.poll()) != null) {

        dispatch(eventWithSubscriber.event, eventWithSubscriber.subscriber);

      }

    } finally {

      isDispatching.remove();

      eventsToDispatch.remove();

    }

  }

 

  void dispatch(Object event, EventSubscriber wrapper) {

    try {

      wrapper.handleEvent(event);

    } catch (InvocationTargetException e) {

      try {

        subscriberExceptionHandler.handleException(

            e.getCause(),

            new SubscriberExceptionContext(

                this,

                event,

                wrapper.getSubscriber(),

                wrapper.getMethod()));

      } catch (Throwable t) {

        // If the exception handler throws, log it. There isn't much else to do!

        Logger.getLogger(EventBus.class.getName()).log(Level.SEVERE,

             String.format(

            "Exception %s thrown while handling exception: %s", t,

            e.getCause()),

            t);

      }

    }

  }

 

从代码中可以看出,EuventBus并没有进行类似异步调用等负载的事件分发策略,而是串行的发布一个事件,然后通知所有感兴趣的订阅者,中间的任何一个订阅者出现阻塞都将造成Event Bus的阻塞。当然用户可以根据需要自己实现自身的异步操作订阅方法,类似于RemovalListeners. asynchronous方法。

@Subscribe

       publicvoid processEvent(EventA event){

          

           new Thread(new Runnable(){

 

              @Override

              publicvoid run() {

                  while(true){

                     System.out.println("eventA happ");

                     try {

                         Thread.sleep(1000);

                     } catch (InterruptedException e) {

                         e.printStackTrace();

                     }

                  }

                 

              }

             

           }).start();

          

       }

 

EventBus的线程安全性

Event Bus类是线程安全的。

EventBus是作为应用中的一个总的事件总线,因此在多线程的使用应该是普遍的。对于EventBus的线程安全性方面使用了一个 RenentrantReadWriteLock来进行同步。

  privatefinal ReadWriteLock subscribersByTypeLock = new ReentrantReadWriteLock();

 

  publicvoid register(Object object) {

    Multimap<Class<?>, EventSubscriber> methodsInListener =

        finder.findAllSubscribers(object);

    subscribersByTypeLock.writeLock().lock();

    try {

      subscribersByType.putAll(methodsInListener);

    } finally {

      subscribersByTypeLock.writeLock().unlock();

    }

  }

从register方法和上节中贴出的post方法中都可以看到通过subscribersByTypeLock进行了线程同步。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值