Akka拦截接收具有可堆叠的行为

时间:2014-08-01 07:02:17

标签: scala akka slf4j interceptor mdc

Akka和Scala新手在这里,请随时编辑问题,以便清楚地表达我在Scala和Akka领域的意图。

在我展示代码片段之前,我想解决的问题是:我本质上想要为我的团队开发一个通用模块,以便在他们使用Akka演员开发应用程序时使用。我想让它们混合一个特性,它将在运行时扩展它们的接收功能,主要用于记录目的。我遇到了编译错误,我很快就会解释。

但首先,举一个简单的主要内容:

object Test extends App {

   val system = ActorSystem("system")
   val myActor = system.actorOf(Props(new MyActor), "myActor")
   myActor ! "Hello world!"
}

这是团队成员可能在其应用程序中实现的演员的示例实现:

class MyActor extends Actor with ActorLogger {

   override def receive: Receive = {
       case msg => {
          log.info("testing ...")
       }
       case _ => throw new RuntimeException("Runtime Ex")
   }
}

以下是我如何为他们提供混合的共同特征的一个例子:

trait ActorLogger extends Actor {

    val log: DiagnosticLoggingAdapter = Logging(this)

    abstract override def receive: Receive = {

         case msg: Any => {
            if (msg.isInstanceOf[String]) {
              println("enter")
              log.mdc(Map[String, Any]("someKey" -> 123))
              super.receive(msg)
              log.clearMDC()
               println("exit")
            }
          }

         case _ => throw new RuntimeException("Runtime Ex")
    }

}

正如您所看到的,我尝试将数据添加到MDC,如果消息恰好是String(一个基本示例,实际上,我会检查我们自己的某些自定义类型)。

我得到的错误是:

 Error:(29, 16) overriding method receive in trait ActorLogger of type =>   
 MyActor.this.Receive;
 method receive needs `abstract override' modifiers
 override def receive: Receive = {
           ^

这里有什么问题?并且堆叠特性是否有权通过消失来实现这样的目标?如果没有,那么最惯用的方式是什么?

更一般地说,除了"拦截器"之外还有其他模式吗?图案?

感谢您的帮助!

3 个答案:

答案 0 :(得分:6)

没有带akka包的黑客攻击的解决方案:

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!"
}
####记录#2:Hello world!

****** 记录#1:Hello world!

SpecificActor:Hello world!

答案 1 :(得分:4)

aroundReceive用于Akka内部使用,并且可堆叠的trair模式对于这种情况并不舒服。 我建议您使用Receive Pipeline来轻松拦截邮件。

答案 2 :(得分:1)

我认为你需要这样的东西

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)
}

该程序的输出是: Foo消息 吧消息 我什么都不知道

最重要的部分是包裹声明 - akka。因为方法aroundReceive仅限于akka包,所以你必须有some.package.akka,你可以使用该方法aroundReceive。我认为它看起来更像是黑客而不是解决方案而是有效。你可以在Akka本身看到更多这种用法。 akka.DiagnosticActorLogging。但这基本上是你想要堆叠Actors行为的解决方案。