构造函数与 preStart:何时使用哪个?

Posted

技术标签:

【中文标题】构造函数与 preStart:何时使用哪个?【英文标题】:Constructor vs. preStart: when to use which? 【发布时间】:2018-07-26 12:05:53 【问题描述】:

在 Akka 中,您可以在构造函数中初始化 actor 的状态。此外,作为参与者生命周期的一部分,preStart 方法可以被重写以初始化参与者的状态并被调用:

actor 首次启动时,在它开始处理其第一条消息之前 当actor重新启动时,除非postRestart被覆盖不调用它

这两种方式(构造函数和preStart)似乎涵盖了参与者启动阶段的重叠阶段,略有不同的是构造函数保证在重新启动时被调用,而preStart可以跳过,前提是您覆盖 postRestart

关于在哪种情况下使用哪一种,是否有公认的或记录在案的最佳实践或模式?

【问题讨论】:

【参考方案1】:

来自initialization via constructor上的文档:

使用构造函数进行初始化有很多好处。首先,它可以使用val 字段来存储任何在actor实例生命周期内不会改变的状态,从而使actor的实现更加健壮。构造函数在创建调用 actorOf 的 Actor 实例时调用,并且在重新启动时也会调用,因此 Actor 的内部总是可以假设发生了正确的初始化。

来自initialization via preStart上的文档:

actor 的方法preStart() 只在第一个实例的初始化期间直接调用一次,即在创建其ActorRef 时。在重启的情况下,preStart() 会从 postRestart() 调用,因此如果没有被覆盖,preStart() 会在每次重启时被调用。但是,通过覆盖 postRestart() 可以禁用此行为,并确保只有一次调用 preStart()

此模式的一个有用用法是在重新启动期间禁止为子级创建新的ActorRefs。这可以通过覆盖preRestart() 来实现。

如果您希望每次实例化actor时都进行初始化(包括重新启动:在重新启动时,会创建底层actor的新实例),请通过构造函数使用初始化。这方面的示例场景是在创建角色时使用不变状态。

如果您希望仅在创建 Actor 的第一个实例时进行初始化,请通过 preStart 使用初始化并覆盖 postRestart 以不调用 preStart。示例用例是在重新启动时保留子 Actor(默认情况下,preRestart 会停止 Actor 的子代,这就是文档提到此示例用例覆盖 preRestart 的原因)。

【讨论】:

哈,在问之前我还没有深入了解文档。谢谢! 首先,谢谢你的好回答:-) 但是我还有一个问题。假设我使用不停止子代的方法以不触发新 ActorRefs 的生成。重启后actor如何知道孩子的ActorRefs?重新启动的参与者是从头开始创建的,没有旧停止实例的任何状态。它是如何计算出孩子的 ActorRefs 的列表的?

以上是关于构造函数与 preStart:何时使用哪个?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我们需要复制构造函数以及何时应该在 java 中使用复制构造函数

何时使用构造函数,构造函数使用new关键字

何时使用 TestFixtureSetUp 属性而不是默认构造函数?

注入服务的构造函数何时运行?

Vue() 构造函数中的 vuex“存储”与“数据:存储”,哪个最好?

使用 XmlSerializer.Deserialize 反序列化时何时调用类构造函数?