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 = {
^
这里有什么问题?并且堆叠特性是否有权通过消失来实现这样的目标?如果没有,那么最惯用的方式是什么?
更一般地说,除了"拦截器"之外还有其他模式吗?图案?
感谢您的帮助!
答案 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行为的解决方案。