本示例来自于官方示例(https://developer.lightbend.com/start/?group=akka&project=akka-quickstart-java):
下载后解压打开
注意:新版本的akka需要使用jdk8
目录结构:
AkkaQuickstart 类:
package com.lightbend.akka.sample;
import java.io.IOException;
import com.lightbend.akka.sample.Greeter.Greet;
import com.lightbend.akka.sample.Greeter.WhoToGreet;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
public class AkkaQuickstart {
public static void main(String[] args) {
//首先,main该类创建一个akka.actor.ActorSystemActors运行的容器。
//接下来,它创建一个Greeter Actor的三个实例和一个Printer Actor的实例。
final ActorSystem system = ActorSystem.create("helloakka");
try {
//#create-actors
//该actorOf工厂方法创建actor和采用两个参数,称为配置对象Props和一个名称。
final ActorRef printerActor =
system.actorOf(Printer.props(), "printerActor");
final ActorRef howdyGreeter =
system.actorOf(Greeter.props("Howdy", printerActor), "howdyGreeter");
final ActorRef helloGreeter =
system.actorOf(Greeter.props("Hello", printerActor), "helloGreeter");
final ActorRef goodDayGreeter =
system.actorOf(Greeter.props("Good day", printerActor), "goodDayGreeter");
//#create-actors
//#main-send-messages
howdyGreeter.tell(new WhoToGreet("Akka"), ActorRef.noSender());
howdyGreeter.tell(new Greet(), ActorRef.noSender());
howdyGreeter.tell(new WhoToGreet("Lightbend"), ActorRef.noSender());
howdyGreeter.tell(new Greet(), ActorRef.noSender());
helloGreeter.tell(new WhoToGreet("Java"), ActorRef.noSender());
helloGreeter.tell(new Greet(), ActorRef.noSender());
goodDayGreeter.tell(new WhoToGreet("Play"), ActorRef.noSender());
goodDayGreeter.tell(new Greet(), ActorRef.noSender());
//#main-send-messages
System.out.println(">>> Press ENTER to exit <<<");
System.in.read();
} catch (IOException ioe) {
} finally {
system.terminate();
}
}
}
Greeter类:
package com.lightbend.akka.sample;
import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.Props;
import com.lightbend.akka.sample.Printer.Greeting;
//#greeter-messages
public class Greeter extends AbstractActor {
//#greeter-messages
static public Props props(String message, ActorRef printerActor) {
return Props.create(Greeter.class, () -> new Greeter(message, printerActor));
}
//#greeter-messages
static public class WhoToGreet {
public final String who;
public WhoToGreet(String who) {
this.who = who;
}
}
static public class Greet {
public Greet() {
}
}
//#greeter-messages
private final String message;
private final ActorRef printerActor;
private String greeting = "";
public Greeter(String message, ActorRef printerActor) {
this.message = message;
this.printerActor = printerActor;
}
@Override
public Receive createReceive() {
return receiveBuilder()
.match(WhoToGreet.class, wtg -> {
this.greeting = message + ", " + wtg.who;
})
.match(Greet.class, x -> {
//#greeter-send-message
printerActor.tell(new Greeting(greeting), getSelf());
//#greeter-send-message
})
.build();
}
//#greeter-messages
}
//#greeter-messages
Printer类:
package com.lightbend.akka.sample;
import akka.actor.AbstractActor;
import akka.actor.Props;
import akka.event.Logging;
import akka.event.LoggingAdapter;
//#printer-messages
public class Printer extends AbstractActor {
//#printer-messages
static public Props props() {
return Props.create(Printer.class, () -> new Printer());
}
//#printer-messages
static public class Greeting {
public final String message;
public Greeting(String message) {
this.message = message;
}
}
//#printer-messages
private LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
public Printer() {
}
@Override
public Receive createReceive() {
return receiveBuilder()
.match(Greeting.class, greeting -> {
log.info(greeting.message+" ( ̄▽ ̄)~*");
})
.build();
}
//#printer-messages
}
//#printer-messages
运行main方法,控制台输出:
输入enter停止程序。
消息可以是任意类型(任何子类型Object
)。可以发送盒装原始值(如String
,Integer
,Boolean
作为消息等)以及纯数据结构如数组和集合类型。
Hello World Actors使用三种不同的消息:
WhoToGreet
:问候的收件人Greet
:执行问候语的指令Greeting
:包含问候语的消息在定义Actors及其消息时,请记住以下建议:
由于消息是Actor的公共API,因此定义具有良好名称和丰富语义和域特定含义的消息是一种很好的做法,即使它们只是包装您的数据类型。这样可以更容易地使用,理解和调试基于actor的系统。
消息应该是不可变的,因为它们在不同的线程之间共享。
将actor的关联消息作为静态类放在Actor的类中是一种很好的做法。这使得更容易理解actor期望和处理的消息类型。
props
在Actor的类中使用静态方法描述如何构造Actor 也是一种常见的模式。
让我们看看Actor如何实现Greeter
并Printer
演示这些最佳实践。
Greeter.java
实现让我们分解一下功能:
Greeter
类扩展akka.actor.AbstractActor
类并实现createReceive
方法。Greeter
构造函数接受两个参数:String message
,这将构建问候消息时和使用ActorRef printerActor
,这对演员处理问候的输出的参考。receiveBuilder
定义的行为; Actor如何对收到的不同消息做出反应。访问或改变Actor的内部状态是完全线程安全的,因为它受Actor模型的保护。该createReceive
方法应该处理actor期望的消息。在这种情况下Greeter
,它需要两种类型的消息:WhoToGreet
和Greet
。前者将更新greeting
Actor 的状态,后者将触发发送greeting
给Printer
Actor。greeting
变量包含Actor的状态,默认设置为""
。props
方法创建并返回一个Props
实例。Props
是一个配置类,用于指定创建actor的选项,将其视为不可变且因此可自由共享的配方,用于创建可包含关联部署信息的actor。此示例仅传递Actor在构造时所需的参数。我们将props
在本教程后面看到该方法的实际应用。Printer actor
该Printer
实现非常简单:
Logging.getLogger(getContext().getSystem(), this);
。通过这样做,我们可以log.info()
在没有任何额外布线的情况下写入Actor。Greeting
,并记录该消息的内容。在Akka中,您无法使用new
关键字创建Actor的实例。相反,您使用工厂创建Actor实例。工厂不返回一个actor实例,而是一个akka.actor.ActorRef
指向actor实例的引用。这种间接级别在分布式系统中增加了很多功能和灵活性。。
该akka.actor.ActorSystem
工厂是,在一定程度上,类似于Spring的BeanFactory
。它充当actor的容器并管理他们的生命周期。该actorOf
工厂方法创建actor和采用两个参数,称为配置对象Props
和一个名称。
actor和ActorSystem
名字在Akka很重要。例如,您可以将它们用于查找。使用与您的域模型一致的有意义的名称可以更轻松地推断它们。
请注意以下事项:
actorOf
方法。正如我们在上一个主题中讨论的那样,它使用类的静态方法来获取值。提供对新创建的Actor实例的引用。ActorSystem
Printer
props
Printer
Props
ActorRef
Printer
Greeter
,代码创建了三个Actor实例,每个实例都有一个特定的问候消息。注意:在此示例中,Greeter
Actors都使用相同的Printer
实例,但我们可以创建Printer
Actor的多个实例。该示例使用一个来说明消息传递的一个重要概念,我们将在稍后介绍。
接下来,让我们看看如何与actor沟通。
actor是被动的和消息驱动的。在收到消息之前,Actor不会执行任何操作。Actor使用异步消息进行通信。这可确保发件人不会等待收件人处理其邮件。相反,发件人将邮件放在收件人的邮箱中,并可以自由地执行其他工作。Actor的邮箱本质上是一个带有排序语义的消息队列。保留从同一个Actor发送的多个消息的顺序,但可以与另一个Actor发送的消息交错。
您可能想知道Actor在处理消息时正在做什么,即做实际的工作?它处于挂起状态,除了内存之外它不消耗任何资源。再次,展示了Actors的轻量级,高效性。
要将消息放入Actor的邮箱,请使用该tell
方法ActorRef
。例如,Hello World的主类将消息发送到Greeter
Actor
该Greeter
演员也将消息发送给Printer
我们研究了如何创建演员和发送消息。现在,我们来看一下整个Main
课程。
Main
Hello World中的类创建并控制actor。注意使用a ActorSystem
作为容器和actorOf
创建Actors 的方法。最后,该类创建要发送给Actors的消息。