原文:http://rerun.me/2014/10/21/akka-notes-child-actors-and-path/
Actor是完全的繼承結構。你創建的任何Actor肯定都是一個其他Actor的child。
讓我們分析下:
PATH
我們用ActorSystem.actorof創建一個ActorRef并打印出他的path
val actorSystem=ActorSystem("SupervisionActorSystem")
val actorRef=actorSystem.actorOf(Props[BasicLifecycleLoggingTeacherActor])
println (actorRef.path) // (prints) akka://SupervisionActorSystem/user/$a
可以看到,一個path看起來很像是文件系統中的一個文件路徑。
這里的akka是固定的,因為這些都是Akka Actor的地址 - 與**file://**和**http://**前綴差不多(跟協議沒啥關系)
SupervisionActorSystem就是你創建的ActorSystem的名字。
user我們下節再說。
$a是系統為你生成出來的Actor的名字。你對操作系統給你隨機生成的文件名怎么看?很明顯是人都不喜歡,因為你之后還要用這個名字。所以,讓我們給他一個有意義的名字:
val actorRef=actorSystem.actorOf(Props[BasicLifecycleLoggingTeacherActor], "teacherActor")
println (actorRef.path) // (prints) akka://SupervisionActorSystem/user/teacherActor
現在這個路徑(path)看起來差不多了。
CHILD ACTORS
跟從ActorSystem里面創建的頂級actor類似,我們也可以給ActorContext創建child actor。事實上, Actor的容錯能力很大程度上就是靠使用Actor的繼承層次和一個parent管理child actor的生命周期的方式。
現在假設你又一個TeacherSupervisor并且你打算創建一個TeacherActor來作為Supervisor的child,可以用ActorContext.actorof來代替使用ActorSystem.actorof:
class TeacherSupervisor extends Actor with ActorLogging {
val teacherActor=context.actorOf(Props[TeacherActor], "teacherActor")
...
...
基本上,在任何應用里,不像頂層actor,你會創建一堆的child actor - 這意思就是與調用actorSystem.actorof不同,你會調用一堆actorContext.actor
你會注意到child actor的path是akka://SupervisionActorSystem/user/teacherSupervisor/teacherActor,看起來跟給父目錄創建一個子目錄是一樣的。
你什么時候開始創建子Actor?
在你的任務是由子任務或多個子任務組成的時候你就應該創建一個子actor了。在你執行的子任務是一個易錯的時候,你想要隔離他(這樣如果錯了,你能恢復他)的時候你也需要創建一個子actor。當task之間沒有父子關系時,你千萬別創建子actor。
并且,還可以讓子actor創建自己的子actor來代理他們自己的子任務。Actor的創建成本很低但產出卻很高(我們在談supervision的時候可以看到這個)
現在那個PATH中的USER是什么?
作為一個對比,我把ActorSystem比擬成一個Unix文件系統 - 有一個/root目錄,還有其他的/etc,/usr,/bin和其他目錄。
ActorSystem跟那個差不多。他創建一些頂層Actor - 最重要根Actor就是根目錄/, user Actor就是/usrr目錄,一個system Actor就是一個/system目錄。(還有一個/deadLetters來代表DeadLetterActorRef。我們在上一篇里面看到過)
ActorSystem內組合了三個Actor(從ActorRefProvider)。他們是ActorSystem創建的所有actor的根actor。
- systemGuardian actor - 所有在/system下的actor的根
- guardian actor - 所有/user下actor的根
- rootGuardian Actor - systemGuardian和userGuardianactor
的根
/**
* Reference to the supervisor of guardian and systemGuardian; ....
*/
def rootGuardian: InternalActorRef
/**
* Reference to the supervisor used for all top-level user actors.
*/
def guardian: LocalActorRef
/**
* Reference to the supervisor used for all top-level system actors.
*/
def systemGuardian: LocalActorRef
/user(aka) user guardian
任何你在自己程序中像StudentActor或TeacherActor用ActorSystem的actof方法來創建的Actor都直接在/user。這就是之前teacherActor的路徑是/user/teacherActor的原因。
/system(aka) system guardian
當userGuardian死的時候system guardian會將自己關閉。當userGuardian關閉時這是合乎常理的, 他下面所有的業務actor都停掉了所以所有的管理員actor都需要一樣停掉。
我們能看到System Actor被創建在兩個地方 - 意思是在**/system*繼承關系下的actor。
像我們之前看到的,所有發給一個已經終結掉的Actor的消息都會被轉發給一個內部Actor(DeadLetterActor)的郵箱。DeadLetter Actor把每個消息包裝成**DeadLetter*然后發送給EventStream。另一個叫DeadLetterListener的Actor消費所有的DeadLetter并且將其作為一個日志消息發送出去。現在,DeadLetterListener是一個在/system/deadLetterListener下的system Actor。
想想我們之前寫的訂閱了EventStream的日志消息的TestEventListener?他們也是System actor。事實上,所有的akka.logger都是作為System actor來創建的。
class TeacherTest extends TestKit(ActorSystem("UniversityMessageSystem", ConfigFactory.parseString("""akka.loggers = ["akka.testkit.TestEventListener"]""")))
...
...
這個文檔提到所有用配置文件配置的Actor都會在啟動的時候被創建并部署到ActorSystem,躲在/system的保護傘下。當我找到有趣的地方再更新下這個。
/(aka)root guardian
像我們之前看到的,/下的Actor是user和system guardian的父 actor。
雜七雜八
技術上來講,root actor也有個父actor。這個actor的唯一任務就是當root actor失敗是關閉整個ActorSystem。因此他沒有被算在Actor的繼承結構里, Akka項目組叫他:
private[akka] val theOneWhoWalksTheBubblesOfSpaceTime: InternalActorRef = new MinimalActorRef {
...
文章來自微信平臺「麥芽面包」(微信掃描二維碼關注)。未經允許,禁止轉載。
文章列表
![]() |
不含病毒。www.avast.com |