2

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

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

但首先,以一个简单的 main 为例:

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(一个基本示例,实际上,我会检查我们自己的一些自定义类型)。

我得到的错误是:

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

这里有什么问题?可堆叠的特征是否有权离开以实现这样的目标?如果没有,最惯用的方法是什么?

更一般地说,除了“拦截器”模式之外,这里是否应用了另一种模式?

感谢所有的帮助!

4

3 回答 3

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:世界你好!

******记录#1:世界你好!

具体演员:世界你好!

于 2014-08-01T09:45:01.820 回答
4

aroundReceive是供 Akka 内部使用的,可堆叠的 tair 图案对于这种情况不太舒服。我建议您使用Receive Pipeline来轻松拦截消息。

于 2014-11-03T21:23:43.203 回答
1

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.

于 2014-08-01T08:54:23.020 回答