首先明白下面几点:
- ActorSystem是该进程中的Actor的管理者,负责创建和监控所有的actor
- ActorSystem是单例的
- Actor负责通信
如下我们使用Akka实现一个简单的RPC通信,首先我们看下他们交互的流程
如下给出Akka相关的Maven包
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-actor_2.10</artifactId>
<version>2.3.14</version>
</dependency>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-remote_2.10</artifactId>
<version>2.3.14</version>
</dependency>
如下是Master端的代码
class Master extends Actor {
println("constructor invoked")
//该方法在构造器后执行
override def preStart(): Unit = {
println("preStart invoked")
}
// 用于接收消息
override def receive: Receive = {
case "connect" => {
println("a client connected")
sender ! "reply" //为context.sender(),即Worker连接端的actor
}
case "hello" => {
println("hello")
}
}
}
object Master {
def main(args: Array[String]) {
val host = args(0)
val port = args(1).toInt
// 准备配置
val configStr =
s"""
|akka.actor.provider = "akka.remote.RemoteActorRefProvider"
|akka.remote.netty.tcp.hostname = "$host"
|akka.remote.netty.tcp.port = "$port"
""".stripMargin
val config = ConfigFactory.parseString(configStr)
//ActorSystem老大,辅助创建和监控下面的Actor,他是单例的
val actorSystem = ActorSystem("MasterSystem", config)
//创建Actor, 起个名字Master,其会在Worker连接Master的时候使用到
val master = actorSystem.actorOf(Props[Master], "Master")//Master主构造器会执行
master ! "hello" //发送信息
actorSystem.awaitTermination() //让进程等待着, 先别结束
}
}
如下是Worker端的代码
class Worker(val masterHost: String, val masterPort: Int) extends Actor{
var master : ActorSelection = _
//建立连接
override def preStart(): Unit = {
//在master启动时会打印下面的那个协议, 可以先用这个做一个标志, 连接哪个master
//继承actor后会有一个context, 可以通过它来连接
master = context.actorSelection(s"akka.tcp://MasterSystem@$masterHost:$masterPort/user/Master") //需要有/user, Master要和master那边创建的名字保持一致
master ! "connect"
}
override def receive: Receive = {
case "reply" => {
println("a reply form master")
}
}
}
object Worker {
def main(args: Array[String]) {
val host = args(0)
val port = args(1).toInt
val masterHost = args(2)
val masterPort = args(3).toInt
// 准备配置
val configStr =
s"""
|akka.actor.provider = "akka.remote.RemoteActorRefProvider"
|akka.remote.netty.tcp.hostname = "$host"
|akka.remote.netty.tcp.port = "$port"
""".stripMargin
val config = ConfigFactory.parseString(configStr)
//ActorSystem老大,辅助创建和监控下面的Actor,他是单例的
val actorSystem = ActorSystem("WorkerSystem", config)
actorSystem.actorOf(Props(new Worker(masterHost, masterPort)), "Worker")
actorSystem.awaitTermination()
}
}
代码分析:由上面的代码可知,其Worker和Master端创建ActorSystem的方法是类似的,Worker端通过 context.actorSelection获得Master端actor的引用,并和其建立连接通信。而Master又可以在receive方法中获得Worker端的连接的actor,从而实现二者互动。