akka学习--2(生命周期)

394 阅读4分钟

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
  }
}