从其它的网上教程中,我们很容易找到各种 Akka 相关的教程。但是可能是因为自己太笨,都没看明白。 于是自己写下这样一篇笔记,作以记录。 关于 Actor 模型的概念,就不在这里赘述了。 在编写 Akka 代码之前,先要加入 Mave 依赖:
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-actor_2.11</artifactId>
<version>2.4.4</version>
</dependency>
以下是第一个 Akka 代码,非常简单:
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.actor.UntypedActor;
public class HelloAkka {
public static void main(String[] argArr) {
ActorSystem systemObj = ActorSystem.create("helloAkka");
ActorRef actorRef = systemObj.actorOf(Props.create(Actor_SayHello.class));
actorRef.tell("hello Akka!", ActorRef.noSender());
}
}
class Actor_SayHello extends UntypedActor {
@Override
public void onReceive(Object objMsg) throws Exception {
System.out.println("receive : " + objMsg);
}
}
运行 HelloAkka 后,屏幕上会输出:"receive : hello Akka!”。 这个 Actor_SayHello 既是消息的发布者又是消息的接收者,有点自言自语的意思。 这是一个 Akka 的 Hello World 程序,虽然简单,但是基本上没有实用价值。
接下来,修改一下上面的程序,将 Actor_SayHello 改名为 Actor_Master。 然后我们再建立一个 Actor_Slave 类。 Actor_Master 好比是主人,Actor_Slave 好比是仆人, 主人告诉仆人:干活去!
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.actor.UntypedActor;
public class HelloAkka {
public static void main(String[] argArr) {
ActorSystem systemObj = ActorSystem.create("helloAkka");
ActorRef actorRef = systemObj.actorOf(Props.create(Actor_Master.class));
actorRef.tell("hello Akka!", ActorRef.noSender());
}
}
class Actor_Master extends UntypedActor {
@Override
public void onReceive(Object objMsg) throws Exception {
// 注意 : 在这里创建另外一个 Actor,也就是 Actor_Slave
ActorRef slave = this.getContext().actorOf(Props.create(Actor_Slave.class));
slave.tell("go to work!", this.getSelf());
}
}
class Actor_Slave extends UntypedActor {
@Override
public void onReceive(Object objMsg) throws Exception {
if (objMsg.equals("go to work!")) {
// 只有收到 go to work! 这条消息时,
// 才输出 yes sir!
System.out.println("yes sir!");
}
}
}
这样,我们就把消息的发布者和消息的接收者分开了。
下面,玩个更刺激的! 让主人与仆人运行在两个不同的机器上,怎么样? 主人运行在 192.168.1.11 这台机器上,端口号是:4711,而 仆人运行在 192.168.1.12 这台机器上,端口号是:4712。
为此,我们需要再多加一个 Maven 依赖:
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-remote_2.11</artifactId>
<version>2.4.4</version>
</dependency>
首先是主人代码 App_Master:
import akka.actor.ActorRef;
import akka.actor.ActorSelection;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.actor.UntypedActor;
import com.typesafe.config.ConfigFactory;
import java.util.HashMap;
import java.util.Map;
public class App_Master {
public static void main(String[] argArr) {
Map<String, String> propMap = new HashMap<>();
// 这个 RemoteActorRefProvider 是要加上的
propMap.put("akka.actor.provider", "akka.remote.RemoteActorRefProvider");
propMap.put("akka.remote.netty.tcp.hostname", "192.168.1.11");
propMap.put("akka.remote.netty.tcp.port", "4711");
ActorSystem systemObj = ActorSystem.create(
"helloAkka",
ConfigFactory.parseMap(propMap)
);
ActorRef actorRef = systemObj.actorOf(Props.create(Actor_Master.class), "master");
actorRef.tell("hello Akka!", ActorRef.noSender());
}
}
class Actor_Master extends UntypedActor {
@Override
public void onReceive(Object objMsg) throws Exception {
// 注意 : 这里是通过 IP 地址拿到 Actor_Slave 的
ActorSelection slave = this.getContext().actorSelection("akka.tcp://helloAkka@192.168.1.12:4712/user/slave");
slave.tell("go to work!", this.getSelf());
}
}
之后是仆人代码 App_Slave:
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.actor.UntypedActor;
import com.typesafe.config.ConfigFactory;
import java.util.HashMap;
import java.util.Map;
public class App_Slave {
public static void main(String[] argArr) {
Map<String, String> propMap = new HashMap<>();
propMap.put("akka.actor.provider", "akka.remote.RemoteActorRefProvider");
propMap.put("akka.remote.netty.tcp.hostname", "192.168.1.12");
propMap.put("akka.remote.netty.tcp.port", "4712");
ActorSystem systemObj = ActorSystem.create(
"helloAkka",
ConfigFactory.parseMap(propMap)
);
ActorRef actorRef = systemObj.actorOf(Props.create(Actor_Slave.class), "slave");
actorRef.tell("hello Akka!", ActorRef.noSender());
}
}
class Actor_Slave extends UntypedActor {
@Override
public void onReceive(Object objMsg) throws Exception {
if (objMsg.equals("go to work!")) {
System.out.println("yes sir!");
}
}
}
注意:先启动仆人 App_Slave,然后再启动主人 App_Master。在仆人那一边,屏幕上会显示:yes sir! 真刺激!