返回介绍

7.2 Akka 之 Hello World

发布于 2024-08-21 22:20:21 字数 3713 浏览 0 评论 0 收藏 0

在了解了Actor的基本行为模式后,我们通过简单的Hello World程序来进一步了解一下Akka的开发。

首先让我们看一下,第1个Actor的实现:

01 public class Greeter extends UntypedActor {
02   public static enum Msg {
03   GREET, DONE;
04   }
05
06   @Override
07   public void onReceive(Object msg) {
08   if (msg == Msg.GREET) {
09     System.out.println("Hello World!");
10     getSender().tell(Msg.DONE, getSelf());
11   } else
12     unhandled(msg);
13   }
14 }

上述代码中,定义了一个欢迎者(Greeter)Actor,它继承自UntypedActor(它自然就是Akka中的核心成员了)。UntypedActor就是我们所说的Actor,之所以这里强调是无类型的,那是因为在Akka中,还支持一种有类型的Actor。有类型的Actor可以使用系统中的其他类型构造,可以缓解Java单继承的问题。因为你在继承了UntypedActor后,就不能再继承系统中的其他类了。如果你一定想这么做,那么就只能选择有类型的Actor。否则,UntypedActor应该就是你的首选。

在这里,代码第2~4行,定义了消息类型。这里只有两种类型,欢迎(GREET)以及完成(DONE)。当Greeter收到GREET消息时,就会在控制台打印“Hello World”,并且向消息发送方发送DONE信息(第10行)。

与Greeter交流的另外一个Actor是HelloWorld,它的实现如下:

01 public class HelloWorld extends UntypedActor {
02   ActorRef greeter;
03
04   @Override
05   public void preStart() {
06     greeter = getContext().actorOf(Props.create(Greeter.class), "greeter");
07     System.out.println("Greeter Actor Path:" + greeter.path());
08     greeter.tell(Greeter.Msg.GREET, getSelf());
09   }
10
11   @Override
12   public void onReceive(Object msg) {
13     if (msg == Greeter.Msg.DONE) {
14       greeter.tell(Greeter.Msg.GREET, getSelf());
15       getContext().stop(getSelf());
16     } else
17       unhandled(msg);
18   }
19 }

上述代码实现了一个名为HelloWorld的Actor。第5行的preStart()方法为Akka的回调方法,在Actor启动前,会被Akka框架调用,完成一些初始化的工作。在这里,我们在HelloWorld中创建了Greeter的实例(第6行),并且向它发送GREET消息(第8行)。此时,由于创建Greeter时使用的是HelloWorld的上下文,因此,它属于HelloWorld的子Actor。

第12行定义的onReceive()函数为HelloWorld的消息处理函数。在这里,只处理DONE的消息。在收到DONE消息后,它会再向Greeter发送GREET消息,接着将自己停止。

因此,Greeter会前后收到两条GREET消息,会打印两次“Hello World”。

最后,让我们看一下主函数main():

1 public class HelloMainSimple {
2   public static void main(String[] args) {
3   ActorSystem system = ActorSystem.create("Hello",ConfigFactory.load("samplehello.conf"));
4     ActorRef a = system.actorOf(Props.create(HelloWorld.class),"helloWorld");
5     System.out.println("HelloWorld Actor Path:" + a.path());
6   }
7 }

程序第3行,创建了ActorSystem,表示管理和维护Actor的系统。一般来说,一个应用程序只需要一个ActorSystem就够用了。ActorSystem.create()的第1个参数“Hello”为系统名称,第2个参数为配置文件。

第4行通过ActorSystem创建一个顶级的Actor(HelloWorld)。

配置文件samplehello.conf的内容如下:

akka {
   loglevel = INFO
}

在这里,只是简单地配置了一下日志级别为INFO。

执行上述代码,可以看到以下输出:

1 HelloWorld Actor Path:akka://Hello/user/helloWorld
2 Greeter Actor Path:akka://Hello/user/helloWorld/greeter
3 Hello World!
4 Hello World!
5 [INFO] [05/13/2015 21:15:01.299] [Hello-akka.actor.default-dispatcher-2]
[akka://Hello/user/helloWorld] Message [geym.akka.demo.hello.Greeter$Msg] from
Actor[akka://Hello/user/helloWorld/greeter#-1698722495] to
Actor[akka://Hello/user/helloWorld#-1915075849] 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'.

第1行打印了HelloWorld Actor的路径。它是系统内第1个被创建的Actor。它的路径为:akka://Hello/user/helloWorld。其中第1个Hello表示ActorSystem的系统名,可以看一下我们构造这ActorSystem时,传入的第1个参数就是Hello。接着user表示用户Actor。所有的用户Actor都会挂载在user这个路径下。第3个helloWorld就是这个Actor的名字。

同理,第2个Greeter Actor的路径结构和HelloWorld是完全一致的。输出的第3、4行显示了Greeter打印的两条信息。第5行表示系统遇到了一条消息投递失败,失败的原因是HelloWorld将自己终止了,导致Greeter发送的信息无法投递。

可以看到,当使用Actor进行并行程序开发时,我们的关注点已经不在线程上了。实际上,线程调度已经被Akka框架进行封装,我们只需要关注Actor对象即可。而Actor对象之间的交流和普通的对象的函数调用有明显区别。它们是通过显示的消息发送来传递信息的。

当系统内有多个Actor存在时,Akka会自动在线程池中选择线程来执行我们的Actor。因此,多个不同的Actor有可能会被同一个线程执行,同时,一个Actor也有可能被不同的线程执行。因此,一个值得注意的地方是:不要在一个Actor中执行耗时的代码,这样可能会导致其他Actor的调度出现问题。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文