actor生命周期
介绍说明
actor本身拥有状态,需要显示启动停止。当一个actor不被引用时,不会自动销毁。父actor销毁,会递归销毁子actor。当ActorSystem销毁,所有的actor都会被销毁。
ActorSystem在一个逻辑应用程序,创建一个,是底层父actor,分配线程资源。一般一个jvm,一个ActorSystem
创建actor
Actor可以创建生成任意数量子Actor,子Actor又可以生成子子Actor,从而形成Actor层次结构。Actor这种层次结构,ActorSystem位于顶层位置,有且只有一个。子Actor声明周期与父Actor紧密关联,子Actor可以随时销毁(主动或者被动),但是子Actor销毁一定比父Actor早。
ActorContext
ActorContext有很多功能,如下所示:
- 生成子Actor,并进行监督
- 监视其它Actor,当被监视Actor销毁,则收到Terminated消息
- 打印日志
- 消息适配器
- 请求响应模式(ask)与其它Actor互动
- 获取本身ActorRef(getSelf())
可以在构造方法,或者setup方法通过ActorContext创建子Actor。
- scala
object HelloWorldMain{
final case class SayHello(name:String)
def apply():Behavior[SayHello] = {
Behaviors.setup{
context =>
val greeter = context.spawn(HelloWorld(),"greeter")
Behaviors.receiveMessage{
message =>
context.log.info("HelloWorldMain message is {}",message)
val replyTo = context.spawn(HelloWorldBot(max = 3),message.name)
greeter ! HelloWorld.Greet(message.name,replyTo)
Behaviors.same
}
}
}
}
- java
package com.scala.study.akka.instruction.java;
import akka.actor.typed.ActorRef;
import akka.actor.typed.ActorSystem;
import akka.actor.typed.Behavior;
import akka.actor.typed.javadsl.AbstractBehavior;
import akka.actor.typed.javadsl.ActorContext;
import akka.actor.typed.javadsl.Behaviors;
import akka.actor.typed.javadsl.Receive;
public class HelloWorldMain extends AbstractBehavior<HelloWorldMain.SayHello> {
private final ActorRef<HelloWorld.Greet> greeter;
public HelloWorldMain(ActorContext<SayHello> context) {
super(context);
greeter = context.spawn(HelloWorld.create(), "greeter");
}
public static Behavior<SayHello> create() {
return Behaviors.setup(HelloWorldMain::new);
}
@Override
public Receive<SayHello> createReceive() {
return newReceiveBuilder()
.onMessage(
SayHello.class,
this::onStart
)
.build();
}
private Behavior<SayHello> onStart(SayHello command) {
ActorRef<HelloWorld.Greeted> replyTo = getContext().spawn(HelloWorldBot.create(3), command.name);
greeter.tell(new HelloWorld.Greet(command.name, replyTo));
return this;
}
public static class SayHello {
public final String name;
public SayHello(String name) {
this.name = name;
}
}
public static void main(String[] args) {
final ActorSystem<SayHello> system = ActorSystem.create(HelloWorldMain.create(), "hello");
system.tell(new HelloWorldMain.SayHello("World"));
}
}
ActorContext 线程安全说明
ActorContext多个方法,都不是线程安全的,在使用ActorContext时最好遵守以下几点
- 不要在future(scala.concurrent.Future)中通过callback调用
- 不要在多个Actor实例共享
- 在普通Actor处理小时时,调用ActorContext方法
底层Actor
顶层Actor,通过ActorSystem创建,发送给ActorSystem消息,直接发送到底层Actor。
- scala
val system : ActorSystem[HelloWorldMain.SayHello] = ActorSystem(HelloWorldMain(),"hello")
system ! HelloWorldMain.SayHello("world")
- java
final ActorSystem<SayHello> system = ActorSystem.create(HelloWorldMain.create(), "hello");
system.tell(new HelloWorldMain.SayHello("World"));
在简单的系统中,根Actor可能会包含引用逻辑并处理消息。系统复杂,则在启动应用时,则会同时生成子Actor,形成Actor层级结构,一起完成业务处理。当根Actor销毁,则ActorSystem也会销毁。
生成子actor
子actor通过父actor的context方法spawn进行创建启动。在以下的例子中,当HelloWorld启动时,创建子actor(greeter),接收到消息创建子actor(replyTo)
object HelloWorldMain{
final case class SayHello(name:String)
def apply():Behavior[SayHello] = {
Behaviors.setup{
context =>
//指定dispather
//val dispatcherPath = "akka.actor.default-blocking-io-dispatcher"
//val props = DispatcherSelector.fromConfig(dispatcherPath)
//val greeter = context.spawn(HelloWorld(), "greeter", props)
val greeter = context.spawn(HelloWorld(),"greeter")
Behaviors.receiveMessage{
message =>
context.log.info("HelloWorldMain message is {}",message)
val replyTo = context.spawn(HelloWorldBot(max = 3),message.name)
greeter ! HelloWorld.Greet(message.name,replyTo)
Behaviors.same
}
}
}
}
public class HelloWorldMain extends AbstractBehavior<HelloWorldMain.SayHello> {
private final ActorRef<HelloWorld.Greet> greeter;
public HelloWorldMain(ActorContext<SayHello> context) {
super(context);
greeter = context.spawn(HelloWorld.create(), "greeter");
}
public static Behavior<SayHello> create() {
return Behaviors.setup(HelloWorldMain::new);
}
@Override
public Receive<SayHello> createReceive() {
return newReceiveBuilder()
.onMessage(
SayHello.class,
this::onStart
)
.build();
}
private Behavior<SayHello> onStart(SayHello command) {
ActorRef<HelloWorld.Greeted> replyTo = getContext().spawn(HelloWorldBot.create(3), command.name);
greeter.tell(new HelloWorld.Greet(command.name, replyTo));
return this;
}
public static class SayHello {
public final String name;
public SayHello(String name) {
this.name = name;
}
}
public static void main(String[] args) {
final ActorSystem<SayHello> system = ActorSystem.create(HelloWorldMain.create(), "hello");
system.tell(new HelloWorldMain.SayHello("World"));
}
}
关闭actor
actor处理消息状态变迁为Behaviors.stopped,则会关闭;父actor关闭,则所有的子actor都会关闭。当actor关闭,则会接收postStop信号,用来清理资源。
package com.scala.study.akka.instruction.scala
import akka.actor.typed.{ActorSystem, Behavior, PostStop}
import akka.actor.typed.scaladsl.Behaviors
import com.scala.study.akka.instruction.scala.MasterControlProgram.{GracefulShutdown, SpawnJob}
object MasterControlProgram {
sealed trait Command
final case class SpawnJob(name: String) extends Command
case object GracefulShutdown extends Command
def apply(): Behavior[Command] = {
Behaviors
.receive[Command]{
(context,message) =>
message match {
case SpawnJob(jobName) => {
context.log.info("Spawning job {}!",jobName)
context.spawn(Job(jobName), name = jobName)
Behaviors.same
}
case GracefulShutdown =>
context.log.info("Initiating graceful shutdown...")
Behaviors.stopped
}
}
.receiveSignal{
case (context,PostStop) => {
context.log.info("Master Control Program stopped")
Behaviors.same
}
}
}
}
object Job{
sealed trait Command
def apply(name:String) : Behavior[Command] = {
Behaviors.receiveSignal[Command]{
case (context,PostStop) =>
context.log.info("WOrker {} stopped",name)
Behaviors.same
}
}
}
object Main{
def main(args: Array[String]): Unit = {
val masterControl = ActorSystem(MasterControlProgram(), "masterControl")
masterControl ! SpawnJob("firstJob")
masterControl ! GracefulShutdown
}
}
观察actor
当一个actor停止,可以向观察它的actor发送消息。用watch,或者watchwith,watch接收信号,watchwith接收指定的消息。
package com.scala.study.akka.instruction.scala
import akka.actor.typed.{ActorSystem, Behavior, PostStop, Terminated}
import akka.actor.typed.scaladsl.Behaviors
import com.scala.study.akka.instruction.scala.JobWatch.JobShutDown
import com.scala.study.akka.instruction.scala.MasterControlProgramWatch.{GracefulShutdown, SpawnJob, SpawnWithJob}
object MasterControlProgramWatch {
sealed trait Command
final case class SpawnJob(name: String) extends Command
final case class SpawnWithJob(name: String) extends Command
private final case class JobTerminated(name: String) extends Command
case object GracefulShutdown extends Command
def apply(): Behavior[Command] = {
Behaviors
.receive[Command] {
(context, message) =>
message match {
case SpawnJob(jobName) => {
context.log.info("Spawning job {}!", jobName)
val jobActor = context.spawn(JobWatch(jobName), name = jobName)
context.watch(jobActor)
Behaviors.same
}
case SpawnWithJob(jobName) => {
context.log.info("SpawnWithJob job {}!", jobName)
val jobActor = context.spawn(JobWatch(jobName), name = jobName)
jobActor ! JobShutDown
context.watchWith(jobActor,JobTerminated("watch sotp"))
Behaviors.same
}
case GracefulShutdown =>
context.log.info("Initiating graceful shutdown...")
Behaviors.stopped
case JobTerminated(name)=>
context.log.info("SpawnWithJob job back {}!", name)
Behaviors.same
}
}
.receiveSignal {
case (context, PostStop) => {
context.log.info("Master Control Program stopped")
Behaviors.same
}
case (context, Terminated(ref)) =>
context.log.info("Job stopped:{}", ref.path.name)
Behaviors.same
}
}
}
object JobWatch {
sealed trait Command
case object JobShutDown extends Command
def apply(name: String): Behavior[Command] = {
Behaviors
.receive[Command] {
(context, message) => {
message match {
case JobShutDown => {
Behaviors.stopped
}
}
}
}
.receiveSignal {
case (context, PostStop) =>
context.log.info("WOrker {} stopped", name)
Behaviors.same
}
}
}
object WathMain {
def main(args: Array[String]): Unit = {
val masterControl = ActorSystem(MasterControlProgramWatch(), "masterControl")
// masterControl ! SpawnJob("firstJob")
masterControl ! SpawnWithJob("SecondJob")
//masterControl ! GracefulShutdown
}
}