Actor DSL

The Actor DSL

简单的actor——例如一次性worker甚或至在REPL中尝试的事物——可以更简洁地使用Act特质创建。支持的基础设施通过以下导入绑定:

  1. import akka.actor.ActorDSL._
  2. import akka.actor.ActorSystem
  3. implicit val system = ActorSystem("demo")

在这一节的所有代码示例都假定有此导入。下面的所有示例中隐式actor系统都作为ActorRefFactory提供服务。要定义一个简单的actor,以下代码就足够了:

  1. val a = actor(new Act {
  2. become {
  3. case "hello" sender() ! "hi"
  4. }
  5. })

在这里,actor方法,根据其调用的上下文,取代了system.actorOf
context.actorOf:它需要一个隐式的 ActorRefFactory,其中在actor内可以通过以下方式获取implicit val context: ActorContext。在actor外,你不得不要声明隐式的ActorSystem,或者你可以显式地提供工厂(具体参见下文)。

两种发起context.become(更换或添加新的行为)的可能方式是分别提供的,从而支持不凌乱的嵌套接收标记语法:

  1. val a = actor(new Act {
  2. become { // this will replace the initial (empty) behavior
  3. case "info" sender() ! "A"
  4. case "switch"
  5. becomeStacked { // this will stack upon the "A" behavior
  6. case "info" sender() ! "B"
  7. case "switch" unbecome() // return to the "A" behavior
  8. }
  9. case "lobotomize" unbecome() // OH NOES: Actor.emptyBehavior
  10. }
  11. })

请注意,调用 unbecomebecomeStacked 次数多将导致原始行为被安装,对Act特质来说是空行为(外部become只是在构造过程中替换它)。

生命周期管理

生命周期挂钩也可以暴露为 DSL 元素使用 (见启动Hook终止Hook),在那里如下所示的调用方法可以取代各自挂钩的内容:

  1. val a = actor(new Act {
  2. whenStarting { testActor ! "started" }
  3. whenStopping { testActor ! "stopped" }
  4. })

如果actor的逻辑生命周期匹配重新启动周期(即 whenStopping 在重新启动之前执行,并且whenStarting在重启之后执行),上面的代码就足够了。如果这不是所期望的,可以使用下面的两个挂钩(请参阅重启Hook):

  1. val a = actor(new Act {
  2. become {
  3. case "die" throw new Exception
  4. }
  5. whenFailing { case m @ (cause, msg) testActor ! m }
  6. whenRestarted { cause testActor ! cause }
  7. })

另外还可以创建嵌套actors,即孙子actor,像这样:

  1. // here we pass in the ActorRefFactory explicitly as an example
  2. val a = actor(system, "fred")(new Act {
  3. val b = actor("barney")(new Act {
  4. whenStarting { context.parent ! ("hello from " + self.path) }
  5. })
  6. become {
  7. case x testActor ! x
  8. }
  9. })

注意

在某些情况下必须显式传递ActorRefFactoryactor()方法(当编译器告诉你出现了模糊蕴涵(implicits)时,你会发现的)。

孙子actor会被子actor监管;此外这类关系的监管策略也可以使用 DSL 元素进行配置(监管指令是Act特质的一部分):

  1. superviseWith(OneForOneStrategy() {
  2. case e: Exception if e.getMessage == "hello" Stop
  3. case _: Exception Resume
  4. })
Stash的actor

最后并且很重要的一点是:还有一点像魔法一样方便的内置,可以检测静态给定的actor子类型的运行时类,是不是通过Stash特质扩展 RequiresMessageQueue特质(这是一个复杂表述,即new Act with Stash不能工作,因为它的运行时类型被擦除为Act的匿名子类型)。目的是为自动根据Stash的需要使用适当的基于deque的邮箱类型。如果你想要使用这个魔法,只需扩展 ActWithStash

  1. val a = actor(new ActWithStash {
  2. become {
  3. case 1 stash()
  4. case 2
  5. testActor ! 2; unstashAll(); becomeStacked {
  6. case 1 testActor ! 1; unbecome()
  7. }
  8. }
  9. })