Google Guava EventBus用于事件编程

在任何软件应用程序中都是如此,有些对象需要共享信息才能完成工作。 在Java应用程序中,实现信息共享的一种方法是拥有事件侦听器,其唯一目的是在发生所需事件时采取某些措施。 在大多数情况下,此过程有效,并且最有经验的Java开发人员习惯于编写实现某些事件侦听器接口的必需的匿名内部类。 这篇文章是关于使用Guava的EventBus处理Java事件的另一种方法。 EventBus允许对象订阅发布事件,而无需彼此明确了解。 EventBus并不旨在成为通用的发布/订阅系统,也不支持进程间通信。

EventBus类别

EventBus非常灵活,可以用作单例,或者应用程序可以具有多个实例以适应在不同上下文中传输事件。 EventBus将按顺序分派所有事件,因此,保持事件处理方法的轻量化很重要。 如果需要在事件处理程序中进行更重的处理,则可以使用EventBus的另一种形式,即AsyncEventBus。 AsyncEventBus在功能上是相同的,但是采用ExecutorService作为构造函数参数来允许事件的异步调度。

订阅活动

对象通过以下步骤预订事件:

  1. 定义一个采用所需事件类型的单个参数的公共方法,并在该方法上放置@Subscribe批注。
  2. 通过将对象的实例传递给EventBus.register方法来向EventBus注册。

这是一个简短的示例,为清楚起见省略了详细信息:

public class PurchaseSubscriber {
    @Subscribe
    public void handlePurchaseEvent(PurchaseEvent event) {
       .....
    }
   .....

  EventBus eventBus = new EventBus();
  PurchaseSubscriber purchaseSubscriber = new PurchaseSubscriber();
  eventBus.register(purchaseSubscriber);

还有一个可以与@Subscribe结合使用的注释,即@AllowConcurrentEvents。 @AllowConcurrentEvents将处理程序方法标记为线程安全的,因此EventBus(很可能是AsyncEventBus)可以潜在地从同时线程调用事件处理程序。 我在单元测试中发现的一件有趣的事情是,如果处理程序方法没有@AllowConcurrentEvents批注,则即使使用AsyncEventBus,它也会按顺序调用事件的处理程序。 重要的是要注意,@ AllowConcurrentEvents不会将方法标记为事件处理程序,@ Subscribe批注仍需要存在。 最后,事件处理方法必须具有一个且只有一个参数,否则当您在EventBus中注册对象时,将抛出IllegalArgumentException。

发布事件

同样,使用EventBus发布事件也很简单。 在您要发送事件通知的代码部分中,调用EventBus.post,将为该事件对象注册的所有订阅者进行通知。

public void handleTransaction(){
    purchaseService.purchase(item,amount);
    eventBus.post(new CashPurchaseEvent(item,amount));
    ....
  }

尽管这很明显,但是订阅类和发布类共享同一EventBus实例很重要,并且使用Guice或Spring帮助管理依赖项是有意义的。

有关事件处理程序的更多信息

EventBus的一项非常强大的功能是,您可以根据需要使处理程序正常运行或细化。 EventBus将为已发布事件对象的所有子类型和已实现的接口调用注册的订户。 例如,要处理所有事件,可以创建一个带有Object类型参数的事件处理程序。 要仅处理单个事件,请创建一个特定于类型的处理程序。 为了帮助说明,请考虑以下简单事件层次结构:

public abstract class PurchaseEvent {
        String item;
   public PurchaseEvent(String item){
       this.item = item;
   }
}

public class CashPurchaseEvent extends PurchaseEvent {
       int amount;
       public CashPurchaseEvent(String item, int amount){
          super(item);
          this.amount = amount;
       }
}

public class CreditPurchaseEvent extends PurchaseEvent {
       int amount;
       String cardNumber;
       public CreditPurchaseEvent(String item,int amount, String cardNumber){
          super(item);
          this.amount = amount;
          this.cardNumber = cardNumber;
       }
}

以下是相应的事件处理类:

//Would only be notified of Cash purchase events
 public class CashPurchaseSubscriber {
     @Subscribe
     public void handleCashPurchase(CashPurchaseEvent event){
      ... 
     }
 }
 //Would only be notified of credit purchases
 public class CreditPurchaseSubscriber {
    @Subscribe
    public void handleCreditPurchase(CreditPurchaseEvent event) {
     ....
    }
}
//Notified of any purchase event
 public class PurchaseSubscriber {
    @Subscribe
    public void handlePurchaseEvent(PurchaseEvent event) {
       .....
    }
}

如果需要捕获各种各样的事件类型,则替代方法是在一个类中具有多个事件处理方法。 拥有多个处理程序可能是一个更好的解决方案,因为您不必对事件对象参数进行任何“ instanceof”检查。 这是我的单元测试中的一个简单示例:

public class MultiHandlerSubscriber {

    List<CashPurchaseEvent> cashEvents = new ArrayList<ashPurchaseEvent>();
    List<CreditPurchaseEvent> creditEvents = new ArrayList<CreditPurchaseEvent>();
    List<SimpleEvent> simpleEvents = new ArrayList<SimpleEvent>();

    public MultiHandlerSubscriber(EventBus eventBus){
        eventBus.register(this);
    }

    @Subscribe
    public void handleCashEvents(CashPurchaseEvent event){
        cashEvents.add(event);
    }

    @Subscribe
    public void handleCreditEvents(CreditPurchaseEvent event){
        creditEvents.add(event);
    }

    @Subscribe
    public void handleSimpleEvents(SimpleEvent event){
        simpleEvents.add(event);
    }
....


测试中

由于事件处理程序只是普通方法,因此可以通过在测试用例中实例化一个EventBus或通过传递适当的事件对象来模拟EventBus来轻松对其进行测试。 当使用EventBus时,我发现很容易:

  • 忘记在EventBus中注册订阅对象
  • 忽略添加@Subscribe批注。

如果似乎未调用事件处理程序,请首先检查这两个错误。
一种有用的调试技术是订阅DeadEvent类。 EventBus将在DeadEvent实例中包装任何没有处理程序的已发布事件。 DeadEvent提供了getEvent方法,该方法返回原始事件对象。

结论

Guava EventBus类为标准Java事件处理机制提供了一种有吸引力且有用的替代方法。 希望读者会发现EventBus像我一样有用。 一如既往地欢迎提出意见和建议。

资源资源


参考:来自我们的JCG合作伙伴 Bill Bejeck的Google Guava EventBus进行事件编程,来自Random Thoughts On Coding博客。

翻译自: https://www.javacodegeeks.com/2012/11/google-guava-eventbus-for-event-programming.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值