原文地址:http://rerun.me/2014/10/21/akka-notes-actor-lifecycle-basic/
(請注意這了討論的生命周期并不包括 preRestart 或者postRestart方法,當我們討論supervision時候我們會說這個)
基本的Actor生命周期很直觀。除了一點小不同,你可以直接拿基本Actor生命周期與Java Servlet生命周期作比較。
- 像其他常規類一樣,我們有一個構造函數。
- preStart方法會被調用。 這里你可以在postStop初始化一些稍后你想清理的資源。
- receive方法用作服務或者消息處理,占用了大部分時間。
先看下一個打印了生命周期的簡單actor。
DUMB LIFECYCLE ACTOR
package me.rerun.akkanotes.lifecycle
import akka.actor.{ActorLogging, Actor}
import akka.event.LoggingReceive
class BasicLifecycleLoggingActor extends Actor with ActorLogging{
log.info ("Inside BasicLifecycleLoggingActor Constructor")
log.info (context.self.toString())
override def preStart() ={
log.info("Inside the preStart method of BasicLifecycleLoggingActor")
}
def receive = LoggingReceive{
case "hello" => log.info ("hello")
}
override def postStop()={
log.info ("Inside postStop method of BasicLifecycleLoggingActor")
}
}
APP
LifecycleApp只初始化,發一個消息給Actor然后關掉ActorSystem.
import akka.actor.{ActorSystem, Props}
object LifecycleApp extends App{
val actorSystem=ActorSystem("LifecycleActorSystem")
val lifecycleActor=actorSystem.actorOf(Props[BasicLifecycleLoggingActor],"lifecycleActor")
lifecycleActor!"hello"
//wait for a couple of seconds before shutdown
Thread.sleep(2000)
actorSystem.shutdown()
}
輸出
Inside BasicLifecycleLoggingActor Constructor
Actor[akka://LifecycleActorSystem/user/lifecycleActor#-2018741361]
Inside the preStart method of BasicLifecycleLoggingActor
hello
Inside postStop method of BasicLifecycleLoggingActor
那個在基礎Actor生命周期與Servlet生命周期的一點不同是什么?
Actor生命周期中的構造函數和preStart是沒什么不一樣的。
我把context.self在構造函數中進行打印的原因就是 - 不像Servlets,Actor在構造函數中可以訪問到ActorContext。而preStart與構造函數間的差別就很微妙了。如果你要打破砂鍋問到底,我們再看下之前說的不同 - 當Actor重啟時(失敗的case)調用preStart是可控的。 用構造函數就不可能了。
什么時候POSTSTOP會被調用?
像我們前面看到的程序, postStrop在ActorSystem關閉時會被調用。還有很多其他的機會能調用到這個回調。
1.ACTORSYSTEM.STOP()
我們可以用ActorSystem的stop方法來停止一個Actor和ActorContext
object LifecycleApp extends App{
val actorSystem=ActorSystem("LifecycleActorSystem")
val lifecycleActor=actorSystem.actorOf(Props[BasicLifecycleLoggingActor],"lifecycleActor")
actorSystem.stop(lifecycleActor);
...
...
}
2.ACTORCONTEXT.STOP
** 1)可以傳個消息(外部或自己給自己傳)**
class BasicLifecycleLoggingActor extends Actor with ActorLogging{
...
...
def receive = LoggingReceive{
case "hello" => log.info ("hello")
case "stop" => context.stop(self)
}
和
object LifecycleApp extends App{
val actorSystem=ActorSystem("LifecycleActorSystem")
val lifecycleActor=actorSystem.actorOf(Props[BasicLifecycleLoggingActor],"lifecycleActor")
lifecycleActor!"stop"
...
...
** 2)或無原因的把自己殺掉(這只是為了好玩。沒有一個有追求的Actor會這么做)
class BasicLifecycleLoggingActor extends Actor with ActorLogging{
log.info ("Inside BasicLifecycleLoggingActor Constructor")
log.info (context.self.toString())
context.stop(self)
...
...
3.毒藥
在之前的例子,我們從LifecycleApp給Actor傳了一個叫stop的消息。Actor在收到消息后用context.stop把自己殺掉。我們也可以通過傳遞一個毒藥(PoisonPill)消息到目標actor來達到同樣的目的。請記住這個毒藥消息,會像前面的stop消息一樣被放在常規mailbox中,當被處理到的時候才會運行。
object LifecycleApp extends App{
val actorSystem=ActorSystem("LifecycleActorSystem")
val lifecycleActor=actorSystem.actorOf(Props[BasicLifecycleLoggingActor],"lifecycleActor")
lifecycleActor!PoisonPill
...
...
4.KILL
除了發送一個毒藥(PoisonPill), 你也可以給目標Actor發送一個kill消息。
lifecycleActor ! Kill
發送毒藥消息和kill消息,區別很微妙但很重要。
- 用PoisonPill,一個Terminated消息會被發送到所有的watcher(稍后我們會在DeathWatch章節中看到)
- 發送kill消息,宿主Actor會拋出一個ActorKilledException并被發送給Supervisor(稍后我們會在Supervision章節中看到)
細枝末節
我前面說的常規mailbox是啥意思?是否還有個“特別”mailbox?是的,確實有!我們會在討論supervision和system消息時說到這個。
TERMINATION
當Actor停止時,他會進入一個Terminated狀態。你馬上就會想到一個問題,那些發到一個已經是terminated狀態的Actor的消息會怎么樣?
讓我們看看:
APP
object LifecycleApp extends App{
val actorSystem=ActorSystem("LifecycleActorSystem")
val lifecycleActor=actorSystem.actorOf(Props[BasicLifecycleLoggingActor],"lifecycleActor")
lifecycleActor!"hello"
lifecycleActor!"stop"
lifecycleActor!"hello" //Sending message to an Actor which is already stopped
}
ACTOR - 與之前一樣
class BasicLifecycleLoggingActor extends Actor with ActorLogging{
def receive = LoggingReceive{
case "hello" => log.info ("hello")
case "stop" => context.stop(self)
}
}
輸出
BasicLifecycleLoggingActor - hello
akka.actor.RepointableActorRef - Message [java.lang.String] from Actor[akka://LifecycleActorSystem/deadLetters] to Actor[akka://LifecycleActorSystem/user/lifecycleActor#-569230546] was not delivered. [1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
從日志中可以看到,這里對deadletters有一些引用。任何你發給那個已經terminated的Actor的消息都會轉發給一個叫DeadLetterActor的內部Actor的mailbox。
那么這之后又發生了什么?
DeadLetter Actor處理它mailbox里的消息,把每個消息都封裝成一個DeadLetter并且把它發布到EventStream中。
另一個叫DeadLetterListener的Actor消費所有的DeadLetter并把它輸出成日志消息。從這里看。
記住,當我們說日志的時候,我們可以看到所有輸出到EventStream的消息并且可以隨意消費 - 只是這個消費者一樣必須是個Actor。讓我們試試。
在我們的例子中,我們消費EventStream并且觀看所有DeadLetter消息最后打印到console(這沒有創造力??)當然,我們還能自由的做任何事如生成告警,把它保存到數據庫或把它拿去作分析。
訂閱EVENTSTREAM的DEADLETTERS
import akka.actor.ActorSystem
import akka.actor.Props
import akka.actor.PoisonPill
import akka.actor.DeadLetter
import akka.actor.Actor
object LifecycleApp extends App {
val actorSystem = ActorSystem("LifecycleActorSystem")
val lifecycleActor = actorSystem.actorOf(Props[BasicLifecycleLoggingActor], "lifecycleActor")
val deadLetterListener = actorSystem.actorOf(Props[MyCustomDeadLetterListener])
actorSystem.eventStream.subscribe(deadLetterListener, classOf[DeadLetter])
lifecycleActor ! "hello"
lifecycleActor ! "stop"
lifecycleActor ! "hello"
}
class MyCustomDeadLetterListener extends Actor {
def receive = {
case deadLetter: DeadLetter => println(s"FROM CUSTOM LISTENER $deadLetter")
}
}
輸出
164 [LifecycleActorSystem-akka.actor.default-dispatcher-4] INFO BasicLifecycleLoggingActor - hello
167 [LifecycleActorSystem-akka.actor.default-dispatcher-4] INFO akka.actor.RepointableActorRef - Message [java.lang.String] from Actor[akka://LifecycleActorSystem/deadLetters] to Actor[akka://LifecycleActorSystem/user/lifecycleActor#-782937925] was not delivered. [1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
FROM CUSTOM LISTENER DeadLetter(hello,Actor[akka://LifecycleActorSystem/deadLetters],Actor[akka://LifecycleActorSystem/user/lifecycleActor#-782937925])
文章來自微信平臺「麥芽面包」(微信掃描二維碼關注)。未經允許,禁止轉載。
文章列表
![]() |
不含病毒。www.avast.com |