Actor 模型及 Akka 简介(三):EventBus简介

EventBus

接下来我们看一个 Actor 的应用:EventBus。在异步处理场景下,运用最为广泛的消息处理模式即是 Pub-Sub 模式。基于 Pub-Sub 模式,还可以根据不同的场景衍生出特殊的模式,例如针对一个 Publisher 和多个 Subscriber,演化为 Broadcast 模式和 Message Router 模式。

EventBus 则通过引入总线来彻底解除 Publisher 与 Subscriber 之间的耦合,类似设计模式中的 Mediator 模式。总线就是 Mediator,用以协调 Publisher 与 Subscriber 之间的关系。对于 Publisher 而言,只需要把消息发布给 EventBus 即可;对于 Subscriber 而言,只需要在 EventBus 注册需要处理的事件并实现处理流程即可。

在没有使用 EventBus 的时候,Publisher 必须显式的调用 Subscriber 的方法。例如订单支付成功后,必须在订单处理模块调用积分模块处理积分,调用服务号模块进行通知。而且这样的显示调用会越来越多,每次都要去修改订单模块加一个调用。这样订单处理模块和那些模块就都紧密耦合在一起了。我们看看 EventBus 怎么解决这个问题。

EventBus 定义

要使用 Akka EventBus, 首先要实现一个 EventBus 接口。

trait EventBus {
  type Event
  type Classifier
  type Subscriber

  //#event-bus-api
  def subscribe(subscriber: Subscriber, to: Classifier): Boolean

  def unsubscribe(subscriber: Subscriber, from: Classifier): Boolean

  def unsubscribe(subscriber: Subscriber): Unit

  def publish(event: Event): Unit
  //#event-bus-api
}

如上所示:

  1. Event 就是需要发布到总线上的事件
  2. Classifier 分类器用于对订阅者进行绑定和筛选
  3. Subscriber 注册到总线上的订阅者。

所幸的是,我们不需要要从头实现 EventBus 接口,Akka 提供了一个 LookupClassification 帮助我们实现 Pub-Sub 模式,我们要做的最主要就是实现 publish 方法。

class XrEventBus extends EventBus with LookupClassification {
  type Event = XrEvent
  type Classifier = XrEventType
  type Subscriber = ActorRef

  override protected def publish(event: Event, subscriber: Subscriber): Unit = {
    subscriber ! event
  }
  // 其他方法...
}

可以看到:

  1. Event 的类型是我们自己定义的 XrEvent。
  2. 分类起是基于 XrEventType,也就是事件类型的。我们系统中定义了很多时间类型,例如 XrEventType.ORDER_PAID 是订单支付事件,XrEventType.DOC_REGISTERED 是用户注册事件。
  3. Subscriber 其实就是一个 Actor。
  4. Publisher 只是简单的将 Event 作为一个消息发布给所有 Subscriber。
事件发布和订阅

Subscriber 这边则需要实现对事件的处理。

class ScoreEventHandler extends Actor with Logging {
  override def receive = {
    // 订单支付成功
    case XrEvent(XrEventType.ORDER_PAID, order: OrderResponse) =>
      // 处理订单支付成功事件

    // 处理其他事件
  }
}

然后我们通过调用 EventBus.subscribe 进行事件订阅。

val eventBus = new XrEventBus

  // 积分事件处理模块
  val scoreEventHandler = XingrenSingletons.akkaSystem.actorOf(
    Props[ScoreEventHandler], name = "scoreEventHandler"))
  eventBus.subscribe(scoreEventHandler, XrEventType.ORDER_PAID)
  // 订阅其他事件..

  // 微信服务号事件处理模块
  val weixinXrEventHandler = XingrenSingletons.akkaSystem.actorOf(
    Props[WeixinXrMessageActor], name = "weixinXrEventHandler"))
  eventBus.subscribe(weixinXrEventHandler, XrEventType.ORDER_PAID)
  // 订阅其他事件..

最后,我们的订单处理模块只需要调用 EventBus.publish 发布订单支付事件就好了。至于那些需要处理该事件的模块,自然会去订阅这个事件。上面 XrEventBus 的实现里可以看到,发布其实就是用 Actor 的消息发送机制,将消息发布给了所有的 Subscriber。

XrEventBus.publish(XrEventType.ORDER_PAID, new OrderResponse(order, product))

至此,我们的订单处理模块和积分处理模块、微信服务号模块就安全解耦了,很漂亮不是吗?

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值