Actor的生命周期
AKKA为Actor生命周期的每个阶段都提供了一个钩子(hook)方法,我们可以通过观察自定义Actor需要重写的方法来理解Actor的生命周期。如下图所示:
Actor被定义为trait,其中一个典型的方法对是preStart()与postStop(),顾名思义,两个方法分别在启动和停止时被调用。在Actor trait中,它们被定义为两个空实现:
trait Actor {
@throws(classOf[Exception]) // when changing this you MUST also change UntypedActorDocTest
//#lifecycle-hooks
def preStart(): Unit = ()
//#lifecycle-hooks
/**
* User overridable callback.
* <p/>
* Is called asynchronously after 'actor.stop()' is invoked.
* Empty default implementation.
*/
@throws(classOf[Exception]) // when changing this you MUST also change UntypedActorDocTest
//#lifecycle-hooks
def postStop(): Unit = ()
//#lifecycle-hooks
}
当然,在Scala中,一个对象的创建总是从构造函数开始的。故而,一个Actor的生命周期依次为:
actorOf -> preStart -> start -> receive -> stop -> postStop
其中actorOf可以控制Actor的创建,它被定义在ActorRefFactory trait中,并分别被ActorSystem与ActorContext实现。在AKKA的早期版本中,提供了actorFor()方法,如今已被标记为deprecated。Remote Actor的创建则有所不同,需要知道该Actor的Path,故而由actorSelection()方法完成。具体关于Actor的创建(准确说来,是ActorRef对象),会在下一节详细介绍。
与之对应的是stop,控制的方式除了显式调用ActorSystem或ActorContext的stop()方法外,还可以通过发送PoisonPill或Kill消息来完成,这几种方式的区别同样留至下一节。
在使用Actor时,其实我们从未察觉到start()方法的存在。这是因为AKKA将其设计为:一旦创建了Actor,就会自动启动,且这种启动方式是异步的。
然而,上述Actor的生命周期不过是一种美丽的假象,正常情况下,我们期待的Actor从诞生到消亡的人生正是如此平淡无奇。但谁的人生不泛起一点点波澜呢?Actor似乎为了体现人生百态,也会怄气,也会撒娇,消极怠工甚至干脆撂挑子罢工。而Actor的控制者,例如ActorContext,或者Actor的supervisior也可能会拿出家长风范,会强行干涉Actor的生活。故而在上图中,我们通过preRestart()与postRestart()这一对方法,可以猜测到Actor可能会处于restart状态。
作为生命周期Restart状态的钩子方法,preRestart()默认行为是在重启(restarting)之前,它会终止所有的children actors(这个过程是递归的)。postRestart()则发生在重启成功之后。当然,方法都可以重写这两个方法以改变其行为。
其实对于Actor的生命周期,在AKKA内部,是通过InternalActorRef来控制的,定义在其中的方法庶几可以透露生命周期管理的信息:
private[akka] abstract class InternalActorRef extends ActorRef with ScalaActorRef { this: ActorRefScope ⇒
/*
* Actor life-cycle management, invoked only internally (in response to user requests via ActorContext).
*/
def start(): Unit
def resume(causedByFailure: Throwable): Unit
def suspend(): Unit
def restart(cause: Throwable): Unit
def stop(): Unit
}
看到这些方法,是否有似曾相识之感呢?Thread的操作与之非常相似。
Akka官方文档提供了说明Actor生命周期的图片,如下所示: