Akka Actor Props 工厂

5

Akka和我正在相互了解。

来自:Akka 2.3.6(当前版本)Actor 推荐实践

这里有一个名为DemoActor的示例演员:

class DemoActor(magicNumber: Int) extends Actor {
  def receive = {
    case x: Int => sender() ! (x + magicNumber)
  }
}

在文档的推荐实践部分中,它表明:“为每个Actor的伴生对象提供工厂方法是一个好主意,这有助于将合适的Props的创建尽可能接近actor定义。” 他们这样做:

object DemoActor {
  def props(magicNumber: Int): Props = Props(new DemoActor(magicNumber))
}

问题像这样指定props方法的工厂有什么区别:

object DemoActor {
  def props(magicNumber: Int): Props = Props(classOf[DemoActor], magicNumber)
}

如果你错过了,不同之处在于Props构造函数的参数:

new DemoActor(magicNumber)

VS

classOf[DemoActor], magicNumber

在akka文档页面的同一部分中,稍微往上一点,在Props section中提到,当使用Props(classOf[ActorWithArgs], "arg1")时:

“在构建Props对象期间,将验证是否存在匹配的构造函数,如果未找到或找到多个匹配的构造函数,则会导致IllegalArgumentEception异常。”

这是好事,不是吗?!?

1个回答

13

这很好,不是吗?!?....

是的,但如果错误可以在编译时捕获,那就更好了。直接调用构造函数的优点是编译器会捕获没有匹配构造函数的问题,而不是在运行时抛出异常。

Props apply 方法的有趣之处在于当你写:

Props(new DemoActor(magicNumber))

当创建Props实例时,演员的构造函数不会立即被调用。构造函数的调用是通过名称而不是通过值进行传递的。您可以在Props apply方法的签名中看到这一点:

def apply[T <: Actor](creator: ⇒ T)(implicit arg0: ClassTag[T]): Props

请注意创建者参数中的右箭头。这允许创建者构造被延迟,并有可能在另一个进程中执行以用于远程actor。

这里存在潜在的风险,如果new操作关闭作用域并捕获一个不打算进行序列化或不可序列化的值,则会使Props对象也不可序列化。这就是为什么文档建议在actor的伴随对象中执行此操作,以最小化意外捕获未打算进行序列化的数据的风险。


非常感谢您提供的出色答案。你让我有了一个“哦,原来如此”的时刻,并且对Akka更加有信心了。感谢您指出Props上的应用程序签名将作为按名称调用。我最初认为在背后的想法是避免classOf [DemoActor](考虑到我以前在Java中的经验,类查找非常昂贵)。在我的情况下,编译时错误的提高是好的,我会把动态查找留给特殊场合,当我真正需要它的时候。再次感谢您的帮助。 - neurozen
1
一个按名称调用的参数在运行时是一个 scala.Function0。Akka如何序列化函数对象? - Yang Bo
我不是完全确定,但我相信字节码实际上是传输然后加载到远程端。只有在没有被非可序列化的闭包捕获上下文的情况下才能正常工作。如果你真的想知道它是如何完成的,我建议将其作为自己的问题提出。 - Eric Zoerner
我发现了一篇非常好的博客文章,它展示了@EricZoerner的答案:https://blog.codecentric.de/en/2017/03/akka-best-practices-defining-actor-props/ - iamsmkr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接