原文地址:http://rerun.me/2014/10/21/akka-notes-actor-lifecycle-basic/

(请注意这了讨论的生命周期并不包括 preRestart 或者postRestart方法,当我们讨论supervision时候我们会说这个)

基本的Actor生命周期很直观。除了一点小不同,你可以直接拿基本Actor生命周期与Java Servlet生命周期作比较。

  1. 像其他常规类一样,我们有一个构造函数。
  2. preStart方法会被调用。 这里你可以在postStop初始化一些稍后你想清理的资源。
  3. receive方法用作服务或者消息处理,占用了大部分时间。

先看下一个打印了生命周期的简单actor。

DUMB LIFECYCLE ACTOR

    package me.rerun.akkanotes.lifecycle

    import akka.actor.{ActorLogging, Actor}
import akka.event.LoggingReceive class BasicLifecycleLoggingActor extends Actor with ActorLogging{ log.info ("Inside BasicLifecycleLoggingActor Constructor")
log.info (context.self.toString())
override def preStart() ={
log.info("Inside the preStart method of BasicLifecycleLoggingActor")
} def receive = LoggingReceive{
case "hello" => log.info ("hello")
} override def postStop()={
log.info ("Inside postStop method of BasicLifecycleLoggingActor")
} }

APP

LifecycleApp只初始化,发一个消息给Actor然后关掉ActorSystem.

import akka.actor.{ActorSystem, Props}

object LifecycleApp extends App{

  val actorSystem=ActorSystem("LifecycleActorSystem")
val lifecycleActor=actorSystem.actorOf(Props[BasicLifecycleLoggingActor],"lifecycleActor") lifecycleActor!"hello" //wait for a couple of seconds before shutdown
Thread.sleep(2000)
actorSystem.shutdown() }

输出

Inside BasicLifecycleLoggingActor Constructor

Actor[akka://LifecycleActorSystem/user/lifecycleActor#-2018741361]

Inside the preStart method of BasicLifecycleLoggingActor

hello

Inside postStop method of BasicLifecycleLoggingActor

那个在基础Actor生命周期与Servlet生命周期的一点不同是什么?

Actor生命周期中的构造函数和preStart是没什么不一样的。

我把context.self在构造函数中进行打印的原因就是 - 不像Servlets,Actor在构造函数中可以访问到ActorContext。而preStart与构造函数间的差别就很微妙了。如果你要打破砂锅问到底,我们再看下之前说的不同 - 当Actor重启时(失败的case)调用preStart是可控的。 用构造函数就不可能了。

什么时候POSTSTOP会被调用?

像我们前面看到的程序, postStrop在ActorSystem关闭时会被调用。还有很多其他的机会能调用到这个回调。

1.ACTORSYSTEM.STOP()

我们可以用ActorSystem的stop方法来停止一个ActorActorContext

object LifecycleApp extends App{

  val actorSystem=ActorSystem("LifecycleActorSystem")
val lifecycleActor=actorSystem.actorOf(Props[BasicLifecycleLoggingActor],"lifecycleActor") actorSystem.stop(lifecycleActor); ...
... }

2.ACTORCONTEXT.STOP

** 1)可以传个消息(外部或自己给自己传)**

class BasicLifecycleLoggingActor extends Actor with ActorLogging{
...
...
def receive = LoggingReceive{
case "hello" => log.info ("hello")
case "stop" => context.stop(self)
}

object LifecycleApp extends App{

  val actorSystem=ActorSystem("LifecycleActorSystem")
val lifecycleActor=actorSystem.actorOf(Props[BasicLifecycleLoggingActor],"lifecycleActor") lifecycleActor!"stop"
...
...

** 2)或无原因的把自己杀掉(这只是为了好玩。没有一个有追求的Actor会这么做)

class BasicLifecycleLoggingActor extends Actor with ActorLogging{

  log.info ("Inside BasicLifecycleLoggingActor Constructor")
log.info (context.self.toString())
context.stop(self)
...
...

3.毒药

在之前的例子,我们从LifecycleApp给Actor传了一个叫stop的消息。Actor在收到消息后用context.stop把自己杀掉。我们也可以通过传递一个毒药(PoisonPill)消息到目标actor来达到同样的目的。请记住这个毒药消息,会像前面的stop消息一样被放在常规mailbox中,当被处理到的时候才会运行。

object LifecycleApp extends App{

  val actorSystem=ActorSystem("LifecycleActorSystem")
val lifecycleActor=actorSystem.actorOf(Props[BasicLifecycleLoggingActor],"lifecycleActor") lifecycleActor!PoisonPill
...
...

4.KILL

除了发送一个毒药(PoisonPill), 你也可以给目标Actor发送一个kill消息。

lifecycleActor ! Kill

发送毒药消息和kill消息,区别很微妙但很重要。

  1. PoisonPill,一个Terminated消息会被发送到所有的watcher(稍后我们会在DeathWatch章节中看到)
  2. 发送kill消息,宿主Actor会抛出一个ActorKilledException并被发送给Supervisor(稍后我们会在Supervision章节中看到)

细枝末节

我前面说的常规mailbox是啥意思?是否还有个“特别”mailbox?是的,确实有!我们会在讨论supervision和system消息时说到这个。


TERMINATION

当Actor停止时,他会进入一个Terminated状态。你马上就会想到一个问题,那些发到一个已经是terminated状态的Actor的消息会怎么样?

让我们看看:

APP

object LifecycleApp extends App{

  val actorSystem=ActorSystem("LifecycleActorSystem")
val lifecycleActor=actorSystem.actorOf(Props[BasicLifecycleLoggingActor],"lifecycleActor") lifecycleActor!"hello"
lifecycleActor!"stop"
lifecycleActor!"hello" //Sending message to an Actor which is already stopped }

ACTOR - 与之前一样

class BasicLifecycleLoggingActor extends Actor with ActorLogging{

  def receive = LoggingReceive{
case "hello" => log.info ("hello")
case "stop" => context.stop(self) }
}

输出

BasicLifecycleLoggingActor - hello 

akka.actor.RepointableActorRef - Message [java.lang.String] from Actor[akka://LifecycleActorSystem/deadLetters] to Actor[akka://LifecycleActorSystem/user/lifecycleActor#-569230546] was not delivered. [1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.

从日志中可以看到,这里对deadletters有一些引用。任何你发给那个已经terminated的Actor的消息都会转发给一个叫DeadLetterActor的内部Actor的mailbox。


那么这之后又发生了什么?

DeadLetter Actor处理它mailbox里的消息,把每个消息都封装成一个DeadLetter并且把它发布到EventStream中。

另一个叫DeadLetterListener的Actor消费所有的DeadLetter并把它输出成日志消息。从这里看

记住,当我们说日志的时候,我们可以看到所有输出到EventStream的消息并且可以随意消费 - 只是这个消费者一样必须是个Actor。让我们试试。

在我们的例子中,我们消费EventStream并且观看所有DeadLetter消息最后打印到console(这没有创造力??)当然,我们还能自由的做任何事如生成告警,把它保存到数据库或把它拿去作分析。

订阅EVENTSTREAM的DEADLETTERS

import akka.actor.ActorSystem
import akka.actor.Props
import akka.actor.PoisonPill
import akka.actor.DeadLetter
import akka.actor.Actor object LifecycleApp extends App { val actorSystem = ActorSystem("LifecycleActorSystem")
val lifecycleActor = actorSystem.actorOf(Props[BasicLifecycleLoggingActor], "lifecycleActor") val deadLetterListener = actorSystem.actorOf(Props[MyCustomDeadLetterListener])
actorSystem.eventStream.subscribe(deadLetterListener, classOf[DeadLetter]) lifecycleActor ! "hello"
lifecycleActor ! "stop"
lifecycleActor ! "hello" } class MyCustomDeadLetterListener extends Actor {
def receive = {
case deadLetter: DeadLetter => println(s"FROM CUSTOM LISTENER $deadLetter")
}
}

输出

164  [LifecycleActorSystem-akka.actor.default-dispatcher-4] INFO  BasicLifecycleLoggingActor - hello 

167  [LifecycleActorSystem-akka.actor.default-dispatcher-4] INFO  akka.actor.RepointableActorRef - Message [java.lang.String] from Actor[akka://LifecycleActorSystem/deadLetters] to Actor[akka://LifecycleActorSystem/user/lifecycleActor#-782937925] was not delivered. [1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'. 

FROM CUSTOM LISTENER DeadLetter(hello,Actor[akka://LifecycleActorSystem/deadLetters],Actor[akka://LifecycleActorSystem/user/lifecycleActor#-782937925])

文章来自微信平台「麦芽面包」(微信扫描二维码关注)。未经允许,禁止转载。

[翻译]AKKA笔记 - ACTOR生命周期 - 基本 -5的更多相关文章

  1. Akka之Actor生命周期

    我们首先来看一下官方给出的Actor的声明周期的图: 在上图中,Actor系统中的路径代表一个地方,其可能会被活着的Actor占据.最初路径都是空的.在调用actorOf()时,将会为指定的路径分配根 ...

  2. [翻译]AKKA笔记 -ACTOR SUPERVISION - 8

    失败更像是分布式系统的一个特性.因此Akka用一个容忍失败的模型,在你的业务逻辑与失败处理逻辑(supervision逻辑)中间你能有一个清晰的边界.只需要一点点工作,这很赞.这就是我们要讨论的主题. ...

  3. [翻译]AKKA笔记 - ACTOR MESSAGING - REQUEST AND RESPONSE -3

    上次我们看Actor消息机制,我们看到开火-忘记型消息发出(意思是我们只要发个消息给Actor但是不期望有响应). 技术上来讲, 我们发消息给Actors就是要它的副作用. 这就是这么设计的.除了不响 ...

  4. Akka(2):Actor生命周期管理 - 监控和监视

    在开始讨论Akka中对Actor的生命周期管理前,我们先探讨一下所谓的Actor编程模式.对比起我们习惯的行令式(imperative)编程模式,Actor编程模式更接近现实中的应用场景和功能测试模式 ...

  5. [翻译]AKKA笔记 - DEATHWATCH -7

    当我们说Actor生命周期的时候,我们能看到Actor能被很多种方式停掉(用ActorSystem.stop或ActorContext.stop或发送一个PoisonPill - 也有一个kill和g ...

  6. akka-typed(1) - actor生命周期管理

    akka-typed的actor从创建.启用.状态转换.停用.监视等生命周期管理方式和akka-classic还是有一定的不同之处.这篇我们就介绍一下akka-typed的actor生命周期管理. 每 ...

  7. 翻译:AKKA笔记 - Actor消息 -1(一)

    从第一篇Akka笔记的介绍中,我们是从很高的高度去观察Akka工具箱中的Actors.在这篇笔记的第二篇,我们会看一下Actors中的消息部分.而且延续上一次的例子,我们还会使用同样的学生与老师的例子 ...

  8. [翻译]AKKA笔记 - CHILD ACTORS与ACTORPATH -6

    原文:http://rerun.me/2014/10/21/akka-notes-child-actors-and-path/ Actor是完全的继承结构.你创建的任何Actor肯定都是一个其他Act ...

  9. [转] Actor生命周期理解

    [转] https://blog.csdn.net/wsscy2004/article/details/38875065 镇图:Actor内功心法图 Actor的生命周期可以用Hooks体现和控制,下 ...

随机推荐

  1. VM(虚拟机安装win7 提示 :units specified don't exist, SHSUCDX can't install)解决方法

    改成IDE的模式

  2. 一步步开发自己的博客 .NET版(10、前端对话框和消息框的实现)

    关于前端对话框.消息框的优秀插件多不胜数.造轮子是为了更好的使用轮子,并不是说自己造的轮子肯定好.所以,这个博客系统基本上都是自己实现的,包括日志记录.响应式布局.评论功能等等一些本可以使用插件的.好 ...

  3. 重撸js_2_基础dom操作

    1.node 方法 返回 含义 nodeName String 获取节点名称 nodeType Number 获取节点类型 nodeValue String 节点的值(注意:文本也是节点) 2.inn ...

  4. Android业务组件化之URL Scheme使用

    前言: 最近公司业务发展迅速,单一的项目工程不再适合公司发展需要,所以开始推进公司APP业务组件化,很荣幸自己能够牵头做这件事,经过研究实现组件化的通信方案通过URL Scheme,所以想着现在还是在 ...

  5. Java 堆内存与栈内存异同(Java Heap Memory vs Stack Memory Difference)

    --reference Java Heap Memory vs Stack Memory Difference 在数据结构中,堆和栈可以说是两种最基础的数据结构,而Java中的栈内存空间和堆内存空间有 ...

  6. 设计模式之行为类模式大PK

                                        行为类模式大PK 行为类模式包括责任链模式.命令模式.解释器模式.迭代器模式.中介者模式.备忘录模式.观察者模式.状态模式.策略 ...

  7. HTML+CSS 项目总结

    在过去的大概一个月的学习,基本掌握了HTML+CSS的用法和特性. 这个星期老师给我们布置了一个PC端的实战项目,并且要求在3-4天内完成,我不惜废寝忘食,在紧迫的时间内大致地完成了,但是有些效果不能 ...

  8. pycharm2016.3.1激活及汉化

    pycharm快捷键 PyCharm设置python新建文件指定编码为utf-8 Python | 设置PyCharm支持中文 0, 注册码 43B4A73YYJ-eyJsaWNlbnNlSWQiOi ...

  9. click事件的累加绑定,绑定一次点击事件,执行多次

    最近做项目为一个添加按钮绑定点击事件,很简单的一个事情,于是我按照通常做法找到元素,使用jquery的on()方法为元素绑定了点击事件,点击同时发送请求.完成后看效果,第一次点击没有问题.再一次点击后 ...

  10. JS案例之2——cycle元素轮播

    元素轮播效果是页面中经常会使用的一种效果.这个例子实现了通过元素的隐藏和显示来表现轮播效果.效果比较简单. 效果图如下: 源代码如下: <!DOCTYPE html> <html&g ...