akka2.3.13です。
actorの初期化について迷ったのですが公式ドキュメントに書いてあったのでまとめます。
モチベ
Actorのフィールドでなんらかの値を初期化する際に以下のパターンが考えられます。 *1
var foo = _ // varで宣言 override preStart() { super.preStart() foo = initFoo // ここで初期化 }
val foo = initFoo // valで宣言&初期化 override preStart() { super.preStart() }
最初はアクターのインスタンスが使いまわされるならrestartのときにコンストラクタが呼ばれないこともありそう・・?みたいな事を思って var foo
方式にしていましたがnull safeじゃない点が気になったので簡単に検証しました。
検証
実行したログをみると、どうもrestartされた際にはプライマリコンストラクタもpreStartもどちらも呼ばれているようです。
公式に書いてあったこと
職場の先輩に公式に書いてあることを教えてもらったので読んでみました。
によると毎回必ず呼ばれるのはむしろプライマリコンストラクタの方で、コードの書き方によってはpreStartの方は呼ばれないこともあるようです。 だいたい意訳な感じのTweetをしたのでご参考まで
なるほどプライマリコンストラクタでやるとvalが使えるけど、Restartのたびに初期化してほしくない物を表現することは出来ない。preStartはsuper.postRestartによって呼ばれるのでpostRestartをオーバーライドしてpreStartを呼ばれなくすれば
— まつちゃら (@matsu_chara) 2016年2月5日
preStartを最初のインスタンス生成時に限定することができる。初期化を一度に限定したいケースの例としては、自分が死んだ時に子アクターを毎回作りなおさずにそのまま保持した時が挙げられる。プライマリコンストラクタでやると毎回子アクターが呼び直されるけど、preStartでやれば
— まつちゃら (@matsu_chara) 2016年2月5日
あとからpostRestartをオーバーライドしてやることで初期化を一回だけに限定することが出来る。
— まつちゃら (@matsu_chara) 2016年2月5日
子アクターの再生成抑止の例ではpreRestartをオーバーライドしてcontext.childrenをstopさせる実装も無効にする必要がある
*1:公式ドキュメントには初期化メッセージを送る方式もありますがここでは省略します。