访问Actor对象的方法和其他对象不同,从来不会得到Actor实例,不调用Actor的方法,也不改变Actor的状态,只向 Actor 发送消息。除此之外,我们也不会直接访问 Actor 的成员,而是通过消息传递来请求获取关于 Actor状态的信息。使用消息传递代替直接方法调用可以加强封装性。
通过使用基于消息的方法,我们可以相当完整地将 Actor 的实例封装起来。如果只通过消息进行相互通信的话,那么永远都不会需要获取 Actor 的实例。我们只需要一种机制来支持向 Actor 发送消息并接收响应。在 Akka 中,这个指向 Actor 实例的引用叫做 ActorRef。 ActorRef 是一个无类型的引用,将其指向的 Actor 封装起来,提供了更高层的抽象,并且给用户提供了一种与 Actor 进行通信的机制。
为了保证能够将 Actor 的实例封装起来,不让其被外部直接访问,我们将所有构造函数的参数传给一个 Props 的实例。
build.sbt
name := "actor"
version := "0.1"
scalaVersion := "2.12.4"
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-actor" % "2.5.16",
"org.scala-lang.modules" %% "scala-java8-compat" % "0.9.0",
"com.typesafe.akka" %% "akka-testkit" % "2.5.16" % Test,
"junit" % "junit" % "4.12" % Test,
"com.novocode" % "junit-interface" % "0.11" % Test,
"org.scalatest" %% "scalatest" % "3.2.0-SNAP10" % Test
)
For scala:
//actor defination
import akka.actor.{Actor, Status}
class ScalaPongActor extends Actor {
override def receive: Receive = {
case "Ping" => sender() ! "Pong"
case _ => sender() ! Status.Failure(new Exception("Unknown Message."))
}
}
For java:
//actor denination
public class JavaPongActor extends AbstractActor {
@Override
public Receive createReceive() {
return ReceiveBuilder.create().
matchEquals("Ping", message -> sender().tell("Pong", ActorRef.noSender()))
.matchAny(x -> sender().tell(new Status.Failure(new Exception("Unkown mesage")), self()))
.build();
}
}
// test the actor
public void test() throws Exception {
ActorSystem actorSystem = ActorSystem.create();
ActorRef actorRef = actorSystem.actorOf(Props.create(JavaPongActor.class));
final CompletionStage cs = toJava(Patterns.ask(actorRef, "Ping", 1000));
final CompletableFuture<String> jFuture = (CompletableFuture<String>) cs;
assertEquals("Pong", jFuture.get());
}