共存

依赖

为了使用 Akka Actor 类型,你需要将以下依赖添加到你的项目中:

1. <!-- Maven -->
2. <dependency>
3. <groupId>com.typesafe.akka</groupId>
4. <artifactId>akka-actor-typed_2.12</artifactId>
5. <version>2.5.23</version>
6. </dependency>

8. <!-- Gradle -->
9. dependencies {
10. compile group: 'com.typesafe.akka', name: 'akka-actor-typed_2.12', version: '2.5.23'
11. }

13. <!-- sbt -->
14. libraryDependencies += "com.typesafe.akka" %% "akka-actor-typed" % "2.5.23"

简介

我们相信 Akka 类型(Typed)将逐渐在现有系统中被采用,因此在同一个ActorSystem中,能够同时使用类型化和非类型化的 Actor 是很重要的。此外,我们不能在一个大爆炸版本(one big bang release)中集成所有现有模块,这也是为什么这两种编写 Actor 的方式必须能够共存的另一个原因。

有两种不同的ActorSystem:akka.actor.ActorSystem和akka.actor.typed.ActorSystem。

目前,类型化的 Actor 系统是通过在表面(hood)下使用非类型化的 Actor 系统来实现的。这在将来可能会改变。

类型化和非类型化可以通过以下方式交互:

  • 非类型化的 Actor 系统可以创建类型化的 Actor
  • 类型化的 Actor 可以向非类型化的 Actor 发送消息,反之亦然
  • 从非类型化的父级生成并监督类型化的子级,反之亦然
  • 从非类型化的 Actor 监视类型化的 Actor,反之亦然
  • 非类型化的 Actor 系统可以转换为类型化的 Actor 系统

示例使用非类型化类的完全限定类名来区分具有相同名称的类型化类和非类型化类。

非类型化到类型化

同时存在的应用程序可能仍然有一个非类型化的ActorSystem。这可以转换为类型化的ActorSystem,以便新代码和迁移的部件不依赖于非类型化的系统:

1. // In java use the static methods on Adapter to convert from typed to untyped
2. import akka.actor.typed.javadsl.Adapter;
3. akka.actor.ActorSystem untypedActorSystem = akka.actor.ActorSystem.create();
4. ActorSystem<Void> typedActorSystem = Adapter.toTyped(untypedActorSystem);

然后,对于新类型化的 Actor,这里介绍如何从未类型化的 Actor 创建、监视并向其发送消息。

1. public abstract static class Typed {
2. interface Command {}

4. public static class Ping implements Command {
5. public final akka.actor.typed.ActorRef<Pong> replyTo;

7. public Ping(ActorRef<Pong> replyTo) {
8. this.replyTo = replyTo;
9. }
10. }

12. public static class Pong {}

14. public static Behavior<Command> behavior() {
15. return Behaviors.receive(Typed.Command.class)
16. .onMessage(
17. Typed.Ping.class,
18. (context, message) -> {
19. message.replyTo.tell(new Pong());
20. return same();
21. })
22. .build();
23. }
24. }

顶级非类型化 Actor 是以通常的方式创建的:

1. akka.actor.ActorSystem as = akka.actor.ActorSystem.create();
2. akka.actor.ActorRef untyped = as.actorOf(Untyped.props());

然后它可以创建一个类型化的 Actor,监视它,并向它发送消息:

1. public static class Untyped extends AbstractActor {
2. public static akka.actor.Props props() {
3. return akka.actor.Props.create(Untyped.class);
4. }

6. private final akka.actor.typed.ActorRef<Typed.Command> second =
7. Adapter.spawn(getContext(), Typed.behavior(), "second");

9. @Override
10. public void preStart() {
11. Adapter.watch(getContext(), second);
12. second.tell(new Typed.Ping(Adapter.toTyped(getSelf())));
13. }

15. @Override
16. public Receive createReceive() {
17. return receiveBuilder()
18. .match(
19. Typed.Pong.class,
20. message -> {
21. Adapter.stop(getContext(), second);
22. })
23. .match(
24. akka.actor.Terminated.class,
25. t -> {
26. getContext().stop(getSelf());
27. })
28. .build();
29. }
30. }

我们导入Adapter类并调用静态方法进行转换。

1. // In java use the static methods on Adapter to convert from typed to untyped
2. import akka.actor.typed.javadsl.Adapter;

要在类型化和非类型化之间转换,akka.actor.typed.javadsl.Adapter中有适配器方法。注意上面示例中的内联注释。

类型化到非类型化

让我们把这个例子颠倒过来,首先创建类型化的 Actor,然后再创建非类型化的 Actor 作为子级。

下面将演示如何创建、监视和向此非类型化 Actor 来回(back and forth)发送消息:

1. public static class Untyped extends AbstractActor {
2. public static akka.actor.Props props() {
3. return akka.actor.Props.create(Untyped.class);
4. }

6. @Override
7. public Receive createReceive() {
8. return receiveBuilder()
9. .match(
10. Typed.Ping.class,
11. message -> {
12. message.replyTo.tell(new Typed.Pong());
13. })
14. .build();
15. }
16. }

创建 Actor 系统和类型化的 Actor:

1. ActorSystem as = ActorSystem.create();
2. ActorRef<Typed.Command> typed = Adapter.spawn(as, Typed.behavior(), "Typed");

然后,类型化的 Actor 创建非类型化的 Actor,监视它并发送和接收响应消息:

1. public abstract static class Typed {
2. public static class Ping {
3. public final akka.actor.typed.ActorRef<Pong> replyTo;

5. public Ping(ActorRef<Pong> replyTo) {
6. this.replyTo = replyTo;
7. }
8. }

10. interface Command {}

12. public static class Pong implements Command {}

14. public static Behavior<Command> behavior() {
15. return akka.actor.typed.javadsl.Behaviors.setup(
16. context -> {
17. akka.actor.ActorRef second = Adapter.actorOf(context, Untyped.props(), "second");

19. Adapter.watch(context, second);

21. second.tell(
22. new Typed.Ping(context.getSelf().narrow()), Adapter.toUntyped(context.getSelf()));

24. return akka.actor.typed.javadsl.Behaviors.receive(Typed.Command.class)
25. .onMessage(
26. Typed.Pong.class,
27. (_ctx, message) -> {
28. Adapter.stop(context, second);
29. return same();
30. })
31. .onSignal(akka.actor.typed.Terminated.class, (_ctx, sig) -> stopped())
32. .build();
33. });
34. }
35. }

监督

非类型化 Actor 的默认监督(supervision)是重新启动,而类型化 Actor 的默认监督是停止。当组合非类型化和类型化 Actor 时,默认监督基于子级的默认行为,即,如果非类型化 Actor 创建类型化子级,则其默认监督将停止;如果类型化的 Actor 创建了非类型化的子级,则其默认监督将是重新启动。


英文原文链接:Coexistence.