Akka intercepting receive with stackable behavior

倾然丶 夕夏残阳落幕 提交于 2019-12-06 09:27:18

A solution without a hack with akka package:

import akka.actor.{Actor, ActorSystem, Props}

trait MyActorExtension extends Actor {

  def receiveExtension: Receive = PartialFunction.empty

}

abstract class MyActor extends MyActorExtension {

  protected def receiveMsg: Receive

  def receive: Receive = receiveExtension orElse receiveMsg

}

trait ActorLogger1 extends MyActor with MyActorExtension {

  abstract override def receiveExtension = {
    case msg =>
      println(s"********** Logging # 1: $msg")
      super.receiveExtension.applyOrElse(msg, receiveMsg)
  }

}

trait ActorLogger2 extends MyActor with MyActorExtension {

  abstract override def receiveExtension = {
    case msg =>
      println(s"########## Logging # 2: $msg")
      super.receiveExtension.applyOrElse(msg, receiveMsg)
  }
}

class SpecificActor extends MyActor with ActorLogger1 with ActorLogger2 {

  def receiveMsg = {
    case someMsg =>
      println(s"SpecificActor: $someMsg")
  }
}

object Test extends App {

  val system = ActorSystem("system")
  val mySpecificActor = system.actorOf(Props(new SpecificActor), "SpecificActor")
  mySpecificActor ! "Hello world!"
}
#### Logging # 2: Hello world!

****** Logging # 1: Hello world!

SpecificActor: Hello world!

aroundReceive is for Akka internal use and the stackable trair pattern is not that comfortable for this case. I recommend you using Receive Pipeline for easy message interception.

I think that you need something like this

package akka

import akka.MsgsProt._
import akka.actor.{ Actor, ActorSystem, Props }

import scala.concurrent.duration._

sealed trait MsgProt
object MsgsProt {
  case object FooMsg extends MsgProt
  case object BarMsg extends MsgProt
}

trait Foo extends Actor {

  override protected[akka] def aroundReceive(receive: Actor.Receive, msg: Any): Unit = msg match {
    case FooMsg => println("Foo message")
    case msg    => super.aroundReceive(receive, msg)
  }
}

trait Bar extends Actor {
  override protected[akka] def aroundReceive(receive: Actor.Receive, msg: Any): Unit = msg match {
    case BarMsg => println("Bar message")
    case msg    => super.aroundReceive(receive, msg)
  }
}

class MyActor extends Actor with Foo with Bar {
  override def receive: Actor.Receive = {
    case _ => println("Nothing I know")
  }
}

object Foo extends App {
  val system = ActorSystem("foobar")
  val myActor = system.actorOf(Props[MyActor])
  implicit val timeout = 2 seconds

  myActor ! FooMsg
  myActor ! BarMsg
  myActor ! "wrong message"

  system.awaitTermination(10 seconds)
}

The output of this program is: Foo message Bar message Nothing I know

Most important part is that package declaration - akka. Because method aroundReceive is limited only to akka package so you have to have some.package.akka and inside you can use that method aroundReceive. I think that it looks more like a hack not a solution but works. You can see more usage of this inside Akka itself ex. akka.DiagnosticActorLogging. But this is basically solution that you want to do with stacking Actors behaviour.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!