本文用到的MyWork的源代码:Akka-2.5.12学习系列(第一个Actor)
本文主要围绕这张图介绍生命周期
Actor 交给开发者的是一个引用,这个引用包括 path和UID,即可定位一个 Actor。
preStart() is invoked after the actor has started but before it processes its first message.
preStart() 在 actor 启动后,处理第一条消息之前被调用。
postStop() is invoked just before the actor stops. No messages are processed after this point.
postStop() 在 actor 停止之前调用,调用后不再接收消息。
preRestart() 在重启 Actor 之前在旧实例上调用
为了控制 Actor 的 restart 和 resume,需要重写 supervisorStrategy() 方法,子 actor 抛出的异常都会被父 actor 接收,对于不同异常可以定义不同的处理方式。这里对 NullPointerException 进行 restart,对 IllegalArgumentException 进行 resume。
import akka.actor.*;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import akka.japi.pf.DeciderBuilder;
import cn.edu.tsinghua.akka.MyWork;
import com.typesafe.config.ConfigFactory;
import scala.concurrent.duration.Duration;
import java.util.concurrent.TimeUnit;
/**
* SuperVisor actor生成RestartActor,并接收RestartActor抛出的异常,并对RestartActor进行处理
*/
public class OverrideHandler extends UntypedAbstractActor{
private LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
ActorRef child = getContext().actorOf(MyWork.props(), "restartActor");
private static SupervisorStrategy strategy =
new OneForOneStrategy(10, Duration.create(1, TimeUnit.MINUTES),
DeciderBuilder
.match(ArithmeticException.class, e -> SupervisorStrategy.resume())
.match(NullPointerException.class, e -> SupervisorStrategy.restart())
.match(IllegalArgumentException.class, e -> SupervisorStrategy.stop())
.matchAny(o -> SupervisorStrategy.escalate())
.build());
@Override
public SupervisorStrategy supervisorStrategy() {
return strategy;
}
@Override
public void onReceive(Object o) throws Throwable {
unhandled(o);
}
public static void main(String[] args) {
ActorSystem system = ActorSystem.create("strategy", ConfigFactory.load("akka.config"));
ActorRef superVisor = system.actorOf(Props.create(OverrideHandler.class), "SuperVisor");
ActorSelection actorSelection = system.actorSelection("akka://strategy/user/SuperVisor/restartActor");//这是akka的路径。restartActor是在SuperVisor中创建的。
actorSelection.tell(MyWork.Msg.RESTART, ActorRef.noSender());
//actorSelection.tell(MyWork.Msg.RESUME, ActorRef.noSender());
}
}
当进行 restart 时,在 MyWork 中打印了uid和path,以及 Object 的 hash 值。可以看出,preStart 和 preRestart 在旧的实例 621249279 上调用,postRestart 在新实例上 1073815171 调用。
MyWork preStart uid=1650273805, path=akka://strategy/user/SuperVisor/restartActor, object hash=621249279
MyWork preRestart uid=1650273805, path=akka://strategy/user/SuperVisor/restartActor, object hash=621249279
MyWork postRestart uid=1650273805, path=akka://strategy/user/SuperVisor/restartActor, object hash=1073815171
当 resume 时,只有 preStart 被调用。
MyWork preStart uid=-357461364, path=akka://strategy/user/SuperVisor/restartActor, object hash=1763940324
节点 Stop 时,会先调用其所有子 actor 的 postStop() 方法。
示例代码:
import akka.actor.*;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import cn.edu.tsinghua.akka.MyWork;
/**
* 当前actor停止前,会先stop掉所有子actor。子actor的postStop()会在当前actor的postStop()之前被调用
*/
public class FatherActor extends AbstractActor {
private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
@Override
public void preStart() {
System.out.println("Father preStart uid=" + getSelf().path().uid() + ", path=" + getSelf().path() + ", object hash=" + this.hashCode());
getContext().actorOf(Props.create(MyWork.class), "second");
}
@Override
public void postStop() {
System.out.println("Father stopped uid=" + getSelf().path().uid() + ", path=" + getSelf().path() + ", object hash=" + this.hashCode());
}
@Override
public Receive createReceive() {
return receiveBuilder()
.matchEquals("stop", s -> {
getContext().stop(getSelf());
})
.matchAny(o -> log.info("received unknown message"))
.build();
}
public static void main(String[] args) {
ActorSystem system = ActorSystem.create("testSystem");
ActorRef first = system.actorOf(Props.create(FatherActor.class), "first");
first.tell("stop", ActorRef.noSender());
}
}
输出为:
Father preStart uid=-256137015, path=akka://testSystem/user/first, object hash=326381712
MyWork preStart uid=1593806360, path=akka://testSystem/user/first/second, object hash=4025049
MyWork stopped uid=1593806360, path=akka://testSystem/user/first/second, object hash=4025049
Father stopped uid=-256137015, path=akka://testSystem/user/first, object hash=326381712
顺便给上pom依赖,没有都用到
<dependency>
<groupId>com.typesafe.akkagroupId>
<artifactId>akka-actor_2.12artifactId>
<version>2.5.12version>
dependency>
<dependency>
<groupId>com.typesafe.akkagroupId>
<artifactId>akka-agent_2.12artifactId>
<version>2.5.12version>
dependency>
<dependency>
<groupId>com.typesafe.akkagroupId>
<artifactId>akka-cluster_2.12artifactId>
<version>2.5.12version>
dependency>
大家有兴趣的可以关注我的公众号(DBDeveloper),涉及分布式数据库、大数据和个人成长分享,欢迎大家一起交流进步