akka actor java_Akka笔记之子Actor及路径

Akka笔记之子Actor及路径

Published:

04 Nov 2014

Category:

Actor是纯粹的分层结构。你所创建出来的Actor必定是某个Actor的子Actor。

我们来简单地分析下:

路径

首先,我们通过ActorSystem.actOf方法来创建一个ActorRef并打印出它的路径。

val actorSystem=ActorSystem("SupervisionActorSystem")

val actorRef=actorSystem.actorOf(Props[BasicLifecycleLoggingTeacherActor])

println (actorRef.path) // (prints) akka://SupervisionActorSystem/user/$a

正如你所看到的,Actor路径跟文件系统的文件路径非常相似。

这里的akka前缀是固定的,因为它们是akka Actor的地址——就像是file://或者http://前缀一样(尽管这跟协议无关)

SupervisionActorSystem就是你创建的ActorSystem的名字。

下一节中我们会讲到这个user到底是什么。

$a是系统给你的Actor自动生成的名字。你会喜欢操作系统随机给你的文件生成名字吗?你肯定不希望这样,因为后续你还需要用这些名字去访问这些Actor。那么,我们来给它取一个有意义的合适的名字:

val actorRef=actorSystem.actorOf(Props[BasicLifecycleLoggingTeacherActor], "teacherActor")

println (actorRef.path) // (prints) akka://SupervisionActorSystem/user/teacherActor

完事了。现在这个路径终于像那么回事儿了。

22b67b06f191bff2d9bdcced2d22493f.png

子Actor

正如从ActorSystem中可以创建出顶层Actor一样,我们也可以通过ActorContext来创建出子Actor。事实上,Actor强大的容错能力恰恰就在于Actor是分层的,并且父Actor可以管理子Actor的生命周期。

假设现在有一个TeacherSupervisor,并且要新建一个TeacherActor作为它的子Actor,那么你就应该调用ActorContext.actorOf方法而非ActorSystem.actorOf:

class TeacherSupervisor extends Actor with ActorLogging {

val teacherActor=context.actorOf(Props[TeacherActor], "teacherActor")

...

...

事实上不管是什么应用,你所创建的子Actor都要远多于顶层Actor——也就是说,调用actorContext.actorOf的时候要远多于actorSystem.actorOf。

9017fd26db498698b051153abdd53fca.png

注意,这个子Actor的路径是akka://SupervisionActorSystem/user/teacherSupervisor/teacherActor,这跟你在父目录中创建一个子目录很像。

什么时候应该创建子Actor?

当某个任务由一个或多个子任务所组成的时候通常就会创建子Actor。或者当某个任务由父Actor执行比较容易出错,而你希望将它进行隔离的时候,也可以使用子Actor(这样当子Actor崩溃的时候,你还能够恢复它)。如果不存在父子Actor关系,就不要创建子Actor。

同样的,你也无法阻止子Actor继续创建子Actor来委派自己的子任务。创建Actor是非常廉价的,但他所带来的意义却非常深远(后面介绍到监督的时候还会继续讲到这点)。

那么路径中的user到底是什么?

由于缺少一个参考物,我们拿ActorSystem来跟Unix文件系统作一下比较——Unix文件系统有一个根目录/以及/etc,/usr,/bin等若干目录。

ActorSystem跟它非常类似。它会创建一些顶层的Actor——最重要的也就是根Actor,它对应路径/,用户Actor对应路径/usr,系统Actor则对应路径/system。(同样还有/deadLetters,它对应的是DeadLetterActorRef)。在我们前一篇文章中已经介绍过它了。

从代码层面来说,ActorSystem由内部的三个Actor组成(通过ActorRefProvider来创建的)。它们是ActorSystem创建的所有Actor的根Actor。

systemGuardian Actor——它是/system下的所有Actor的根

guardian Actor——它是/usr下面的所有Actor的根

rootGuardian Actor——它是systemGuardian和guardian共同的根。

/**

* Reference to the supervisor of guardian and systemGuardian; ....

*/

def rootGuardian: InternalActorRef

/**

* Reference to the supervisor used for all top-level user actors.

*/

def guardian: LocalActorRef

/**

* Reference to the supervisor used for all top-level system actors.

*/

def systemGuardian: LocalActorRef

/usr用户守卫

程序中通ActorSystem的actorOf方法所创建的诸如StudentActor或者TeacherActor等所有Actor都挂在/usr路径下。这就是为什么在本文第一节中你所创建的TeacherActor会在/user/teacherActor下。

/system系统守卫

当系统守卫发现用户守卫已经停止运行的时候它会把自己也终止掉。为什么会这样?因为既然用户守卫都终止了,这说明它下面的所有的业务相关的Actor就都结束运行了,因此所有管理类的Actor也应该停止了。

来看下创建系统Actor的两个不同的场景——系统Actor指的是/system路径下的Actor。

如前所述,发送给已终止Actor的任何消息都会转发到一个叫DeadLetterActor的内部Actor的邮箱里。DeadLetterActor会将每条消息封装成一个DeadLetter消息并发布到EventStream中去。另一个叫DeadLetterListener的Actor会去消费这些DeadLetter消息并将它们作为日志打印出来。这里的DeadLetterListener就是一个系统级的Actor,它的路径是 /system/deadLetterListener。

还记得前篇笔记中我们创建的那个订阅日志消息的TestEventListener吗?它们也是系统Actor。事实上,所有的akka.loggers都是作为系统Actor来创建的。

class TeacherTest extends TestKit(ActorSystem("UniversityMessageSystem", ConfigFactory.parseString("""akka.loggers = ["akka.testkit.TestEventListener"]""")))

...

...

这里的文档说道,配置文件中所配置,创建并部署到ActorSystem中的任何Actor都会落到/system下面。如果后面我发现有什么例外的情况我再更新下这里所说的。

/ 根守卫

如前所述,/ Actor是用户及系统守卫的父Actor。

小知识

从技术上来讲,根Actor也有一个父Actor。它只负责做一件事情,就是当根Actor崩溃的时候去关掉整个ActorSystem。严格来说,由于在Actor结构中并没有提到它,因此Akka团队把它叫作:

private[akka] val theOneWhoWalksTheBubblesOfSpaceTime: InternalActorRef = new MinimalActorRef {

...

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值