7.4 Actor 的生命周期
Actor在系统中产生后,也存在着“生老病死”的活动周期。Akka框架提供了若干回调函数,让我们得以在Actor的活动周期内进行一些业务相关的行为。Actor的生命周期如图7.1所示。
图7.1 Actor的生命周期
一个Actor在actorOf()函数被调用后开始建立,Actor实例创建后,会回调preStart()方法。在这个方法里,我们可以进行一些资源的初始化工作。在Actor的工作过程中,可能会出现一些异常,这种情况下,Actor会需要重启。当Actor被重启时,会回调preRestart()方法(在老的实例上),接着系统会创建一个新的Actor对象实例(虽然是新的实例,但它们都表示同一个Actor)。当新的Actor实例创建后,会回调postRestart()方法,表示启动完成,同时新的实例将会代替旧的实例。停止一个Actor也有很多方式,你可以调用stop()方法或者给Actor发送一个PosionPill(毒药丸)。Actor停止时,postStop()方法会被调用,同时这个Actor的监视者会收到一个Terminated消息。
下面让我们建立一个带有生命周期回调函数的Actor:
public class MyWorker extends UntypedActor { private final LoggingAdapter log = Logging.getLogger(getContext().system(), this); public static enum Msg { WORKING, DONE,CLOSE; } @Override public void preStart(){ System.out.println("MyWorker is starting"); } @Override public void postStop(){ System.out.println("MyWorker is stopping"); } @Override public void onReceive(Object msg) { if (msg == Msg.WORKING) { System.out.println("I am working"); } if (msg == Msg.DONE) { System.out.println("Stop working"); }if (msg == Msg.CLOSE) { System.out.println("I will shutdown"); getSender().tell(Msg.CLOSE, getSelf()); getContext().stop(getSelf()); } else unhandled(msg); } }
上述代码定义了一个名为MyWorker的Actor。它重载了preStart()和postStop()两个方法。一般来说,我们可以使用preStart()来初始化一些资源,使用postStop()来进行资源的释放。这个Actor很简单,当它收到WORKING消息时,就打印“I am working”,收到DONE消息时,打印“Stop working”。
接着,我们为MyWorker指定一个监视者,监视者就如同一个劳动监工,一旦MyWorker因为意外停止工作,监视者就会收到一个通知。
01 public class WatchActor extends UntypedActor { 02 private final LoggingAdapter log = Logging.getLogger(getContext().system(), this); 03 04 public WatchActor(ActorRef ref) { 05 getContext().watch(ref); 06 } 07 08 @Override 09 public void onReceive(Object msg) { 10 if (msg instanceof Terminated) { 11 System.out.println(String.format("%s has terminated, shutting down system", 12 ((Terminated) msg).getActor().path())); 13 getContext().system().shutdown(); 14 } else { 15 unhandled(msg); 16 } 17 } 18 }
上述代码定义了一个监视者WatchActor,它本质上也是一个Actor,但不同的是,它会在它的上下文中watch一个Actor(第5行)。如果将来这个被监视的Actor的退出终止,WatchActor就能收到一条Terminated消息(代码第10行)。在这里,我们将简单地打印终止消息Terminated中的相关Actor路径,并且关闭整个ActorSystem(第13行)。
主函数如下:
01 public class DeadMain { 02 public static void main(String[] args) { 03 ActorSystem system = ActorSystem 04 .create("deadwatch", ConfigFactory.load("samplehello.conf")); 05 ActorRef worker = system.actorOf(Props.create(MyWorker.class), "worker"); 06 system.actorOf(Props.create(WatchActor.class, worker), "watcher"); 07 worker.tell(MyWorker.Msg.WORKING, ActorRef.noSender()); 08 worker.tell(MyWorker.Msg.DONE, ActorRef.noSender()); 09 worker.tell(PoisonPill.getInstance(), ActorRef.noSender()); 10 } 11 }
上述代码中,我们首先创建ActorSystem全局实例(第3~4行),接着创建MyWorker Actor和WatchActor。注意第6行的Props.create()方法,它的第1个参数为要创建的Actor类型,第2个参数为这个Actor的构造函数的参数(在这里,就是要调用WatchActor的构造函数)。接着,向MyWorker先后发送WORKING和DONE两条消息。最后在第9行,发送一条特殊的消息PoisonPill。PoisonPill就是毒药丸,它会直接毒死接收方,让其终止。
执行上述代码,系统输出如下:
MyWorker is starting I am working Stop working MyWorker is stopping akka://deadwatch/user/worker has terminated, shutting down system
从这个输出中可以看到,MyWorker生命周期中的两个回调函数以及消息处理函数都被正常调用。最后一行输出也显示WatchActor正常监视到MyWorker的终止。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论