5、Akka Actor生命周期

Actor生命周期

Actor的生命周期是使用Hooks体现和控制的,我们可以重写相关的Hooks,从而实现对Actor生命周期各环节的细粒度控制,各种Hook顺序关系如下图:
(img-6m9LXV8f-1610516371587)(/Users/lipan/app/typora-pic/image-20210113125834499.png)]

  • prestart():在构造函数之后调用,重启时不会执行。
  • postStop():在重启之前调用,异常重启时不会执行。
  • preRestart(reason, message):在 actor 异常重启前保存当前状态,默认情况下会调用 postStop()。
  • postRestart():在 actor 异常重启后恢复重启前保存的状态,默认情况下会调用 preStart()。
    在这里插入图片描述

示例代码

ParentActor.scala :接收从 Main.scala 里发送的消息,初始化或控制 ChildActor。

package com.lp.akka.notes.lifecycle

import akka.actor.{
    
    Actor, ActorLogging, Props, ReceiveTimeout}

/**
 * @author li.pan
 * @version 1.0.0
 * @Description 父Actor
 * @createTime 2021年01月13日 13:04:00
 */
class ParentActor extends Actor with ActorLogging {
    
    
  println("start pActor ")

  def receive = {
    
    
    case "test" => log.info("received test")
    case ("newChild", name: String) => context.actorOf(Props[ChildActor], name)
    case ("stop", name: String) => {
    
    
      val child = context.actorFor(self.path + "/" + name);
      context.stop(child)
    }
    case ReceiveTimeout => throw new RuntimeException("received timeout"); // 每隔超时时间没收到消息就抛出异常
    case "suicide" =>
    case x: Any => log.info("received unknown message :" + x)
  }

  /**
   * 在 actor 实例化后执行,重启时不会执行
   */
  override def preStart {
    
    
    println("actor:" + self.path + ", parent preStart ")
  }

  /**
   * 在 actor 正常终止后执行,异常重启时不会执行。
   */
  override def postStop {
    
    
    println("actor:" + self.path + ",parent postStop .")
  }

  /**
   * 在 actor 异常重启前保存状态
   */
  override def preRestart(reason: Throwable, message: Option[Any]) {
    
    
    println("actor:" + self.path + ", preRestart parent, reason:" + reason + ", message:" + message)
  }

  /**
   * 在 actor 异常重启后恢复状态
   */
  override def postRestart(reason: Throwable) {
    
    
    println("actor:" + self.path + ", postRestart parent, reason:" + reason)
  }
}

ChildActor.scala:子 Actor,被 ParentActor 控制。

package com.lp.akka.notes.lifecycle

import akka.actor.Actor

/**
 * @author li.pan
 * @version 1.0.0
 * @Description 子 Actor
 * @createTime 2021年01月13日 13:03:00
 */
class ChildActor extends Actor {
    
    

  override def receive() = {
    
    
    case "abc" => println("get abc string ")
    case "exception" => throw new NullPointerException()
    case _ => println("children cann't handle unknown message")
  }

  override def preStart {
    
    
    println("actor:" + self.path + ",child preStart .")
  }

  override def postStop {
    
    
    println("actor:" + self.path + ",child postStop .")
  }

  override def preRestart(reason: Throwable, message: Option[Any]) {
    
    
    println("actor:" + self.path + ",preRestart child, reason:" + reason + ", message:" + message)
  }

  override def postRestart(reason: Throwable) {
    
    
    println("actor:" + self.path + ",postRestart child, reason:" + reason)
  }
}

LifeCycleMainApp:初始化、发送消息给Actor。

package com.lp.akka.notes.lifecycle

import akka.actor.{
    
    ActorSystem, Kill, Props}

/**
 * @author li.pan
 * @version 1.0.0
 * @Description 主类
 * @createTime 2021年01月13日 13:05:00
 */
object LifeCycleMainApp extends App {
    
    

  // 构建Actor系统
  val system = ActorSystem("lpLocalSys")

  // 通过Props方式创建父Actor
  val pActor = system.actorOf(Props[ParentActor], name = "pActor")

  pActor ! ("newChild", "child-1")
  pActor ! ("newChild", "child-2")
  pActor ! "test"

  val parent = system.actorSelection("akka://lpLocalSys/user/pActor")
  parent ! "test"
  //    parent ! ("stop", "child-2")

  val child2 = system.actorSelection("akka://lpLocalSys/user/pActor/child-2")
  child2 ! Kill // 杀死 child2
  //    child2 ! "exception"
  Thread.sleep(5000) // 等待 child2  被杀死
  pActor ! ("newChild", "child-2")
  //    Thread.sleep(5000)
  //    myActor ! ("newChild", "child-2")
}
                                                                             

运行结果:
在这里插入图片描述
在 LifeCycleMainApp 里,如果不等的 child-2 被杀死就创建同名的 actor将导致名为 myactor 的父 actor 异常,使它重启,而根据 Akka Actor 的监管策略,它也会重启它的子 Actor,所以 child-1 和child-2 也会被重启,输出如下
在这里插入图片描述

从输出可以看到:父 Actor 首先调用 preRestart ,然后 被实例化,再调用 postRestart,最后再重启它的子 Actor,子 Actor 也遵循上述的步骤。

参考文献

  • 《Akka入门与实践》
  • https://coderbee.net/index.php/akka/20140814/1000
  • https://www.jianshu.com/p/16de393ec5b4

关注公众号 回复Akka领取《Akka入门与实践》书籍
关注公众号 数据工匠记 ,专注于大数据领域离线、实时技术干货定期分享!个人网站 www.lllpan.top
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/lp284558195/article/details/112560703