前面我们讲到了Actor的[url=http://it.deepinmind.com/akka/2014/10/19/akka-notes-actor-messaging-1.html]消息传递[/url],并看到了如何发送一条fire-n-forget消息(也就是说,消息发送给Actor后我们就不管了,不从Actor那接收响应)。
技术上来讲,消息发送给Actor就是希望能有副作用的。设计上便是如此。目标Actor可以不做响应,也可以做如下两件事情——
1. 给发送方回复一条响应(在本例中,TeacherActor会将一句名言回复给StudentActor)
2. 将响应转发给其它的目标受众Actor,后者也可以进行响应/转发/产生副作用。Router和Supervisor就是这种情况。(很快我们就会看到)
[b]请求及响应[/b]
本文中我们只关注第一点——请求及响应周期。
[img]https://raw.githubusercontent.com/arunma/blogimages/master/Akka3/Complete.png[/img]
这张图说明了我们这次要做的事情。为了简单点,图中我并没有画出ActorSystem, Dispatcher以及Mailbox。
1. DriverApp将一条InitSignal消息发送给StudentActor。
2. StudentActor响应InitSignal消息并将一条QuoteRequest消息发送到TeacherActor。
3. 正如前面所说的那样,TeacherActor会回复一个QuoteResponse。
4. StudentActor将日志打印到控制台或者logger里。
同样的,我们会写一个测试用例来验证下它。
现在我们来仔细地分析下这四个步骤:
[b] 1. DRIVERAPP将一条INITSIGNAL消息发送给STUDENTACTOR[/b]
[img]https://raw.githubusercontent.com/arunma/blogimages/master/Akka3/DriverApp.png[/img]
现在你应该能猜到DriverApp到底是干什么的了。它只做了4件事情:
1. 初始化ActorSystem
2. 创建TeacherActor
3. 创建StudentActor
你会注意到我把TeacherActor的一个ActorRef的引用作为构造函数的参数传给了StudentActor,这样StudentActor才能够通过ActorRef来将消息发送给TeacherActor。当然还有别的方法(比如通过[url=http://doc.akka.io/api/akka/2.3.1/index.html#akka.actor.Props]Props[/url]来传递),不过这么做对后续即将讲到的Supervisor和Router来说会方便一点。很快我们会看到子Actor也能实现这个功能,不过那个方法用在这里并不适合——学生来生成老师,这看起来不太对劲吧?
最后,
4. DriverApp将InitSignal消息发送给了StudentActor,这样StudentActor会开始将QuoteRequest消息发送给TeacherActor。
DriverClass讲的已经够多了。后面的Thread.sleep和ActorSystem.shutdown就是等了几秒,以便消息发送完成,然后再最终将ActorSystem关掉。
DRIVERAPP.SCALA
[b] 2. STUDENTACTOR响应INITSIGNAL消息并将QUOTEREQUEST消息发送给TEACHERACTOR[/b]
以及
[b] 4. STUDENTACTOR接收到TEACHERACTOR回复的QuoteResponse然后将日志打印到控制台/logger上来[/b]
为什么我把第2和第4点放到一起来讲?因为它太简单了,如果分开讲的话我怕你嫌我啰嗦。
[img]https://raw.githubusercontent.com/arunma/blogimages/master/Akka3/StudentTeacher.png[/img]
那么,第2步——StudentActor接收到DriverApp发过来的InitSingal消息并将QuoteRequest发送给TeacherActor。
搞定!
第4步——StudentActor将TeacherActor发过来的消息打印出来。
[img]https://raw.githubusercontent.com/arunma/blogimages/master/Akka3/Student.png[/img]
说到做到:
我猜你肯定觉得这很像是伪代码。
那么,完整的StudentActor应该是这样的:
STUDENTACTOR.SCALA
[b] 3. TeacherActor回复QuoteResponse[/b]
这和我们在前面的[url=(http://it.deepinmind.com/akka/2014/10/19/akka-notes-actor-messaging-1.html]fire-n-forget那篇[/url])中看到的代码是类似的。
TeacherActor接收到QuoteRequest消息然后回复一个QuoteResponse。
TEACHERACTOR.SCALA
[b] 测试用例[/b]
现在,我们的测试用例会来模拟下DriverApp。由于StudentActor只是打印了个日志消息,我们没法对QuoteResponse本身进行断言,那么我们就看下EventStream中是不是有这条日志消息就好了(就像上回做的那样)
那么,我们的测试用例看起来会是这样的:
[b] 代码[/b]
项目的完整代码可以从[url=https://github.com/arunma/AkkaMessagingRequestResponse]Github[/url]中进行下载。
在下一篇中,我们将会看到如何在Akka中使用调度器以及如何通过[url=http://kamon.io/]Kamon[/url]来监控你的Akka应用。
原创文章转载请注明出处:[url=http://it.deepinmind.com]http://it.deepinmind.com[/url]
[url=http://rerun.me/2014/10/06/akka-notes-actor-messaging-request-and-response-3/]英文原文链接[/url]
技术上来讲,消息发送给Actor就是希望能有副作用的。设计上便是如此。目标Actor可以不做响应,也可以做如下两件事情——
1. 给发送方回复一条响应(在本例中,TeacherActor会将一句名言回复给StudentActor)
2. 将响应转发给其它的目标受众Actor,后者也可以进行响应/转发/产生副作用。Router和Supervisor就是这种情况。(很快我们就会看到)
[b]请求及响应[/b]
本文中我们只关注第一点——请求及响应周期。
[img]https://raw.githubusercontent.com/arunma/blogimages/master/Akka3/Complete.png[/img]
这张图说明了我们这次要做的事情。为了简单点,图中我并没有画出ActorSystem, Dispatcher以及Mailbox。
1. DriverApp将一条InitSignal消息发送给StudentActor。
2. StudentActor响应InitSignal消息并将一条QuoteRequest消息发送到TeacherActor。
3. 正如前面所说的那样,TeacherActor会回复一个QuoteResponse。
4. StudentActor将日志打印到控制台或者logger里。
同样的,我们会写一个测试用例来验证下它。
现在我们来仔细地分析下这四个步骤:
[b] 1. DRIVERAPP将一条INITSIGNAL消息发送给STUDENTACTOR[/b]
[img]https://raw.githubusercontent.com/arunma/blogimages/master/Akka3/DriverApp.png[/img]
现在你应该能猜到DriverApp到底是干什么的了。它只做了4件事情:
1. 初始化ActorSystem
//Initialize the ActorSystem
val system = ActorSystem("UniversityMessageSystem”)
2. 创建TeacherActor
//create the teacher actor
val teacherRef = system.actorOf(Props[TeacherActor], "teacherActor”)
3. 创建StudentActor
//create the Student Actor - pass the teacher actorref as a constructor parameter to StudentActor
val studentRef = system.actorOf(Props(new StudentActor(teacherRef)), "studentActor")
你会注意到我把TeacherActor的一个ActorRef的引用作为构造函数的参数传给了StudentActor,这样StudentActor才能够通过ActorRef来将消息发送给TeacherActor。当然还有别的方法(比如通过[url=http://doc.akka.io/api/akka/2.3.1/index.html#akka.actor.Props]Props[/url]来传递),不过这么做对后续即将讲到的Supervisor和Router来说会方便一点。很快我们会看到子Actor也能实现这个功能,不过那个方法用在这里并不适合——学生来生成老师,这看起来不太对劲吧?
最后,
4. DriverApp将InitSignal消息发送给了StudentActor,这样StudentActor会开始将QuoteRequest消息发送给TeacherActor。
//send a message to the Student Actor
studentRef ! InitSignal
DriverClass讲的已经够多了。后面的Thread.sleep和ActorSystem.shutdown就是等了几秒,以便消息发送完成,然后再最终将ActorSystem关掉。
DRIVERAPP.SCALA
package me.rerun.akkanotes.messaging.requestresponse
import akka.actor.ActorSystem
import akka.actor.Props
import me.rerun.akkanotes.messaging.protocols.StudentProtocol._
import akka.actor.ActorRef
object DriverApp extends App {
//Initialize the ActorSystem
val system = ActorSystem("UniversityMessageSystem")
//construct the teacher actor
val teacherRef = system.actorOf(Props[TeacherActor], "teacherActor")
//construct the Student Actor - pass the teacher actorref as a constructor parameter to StudentActor
val studentRef = system.actorOf(Props(new StudentActor(teacherRef)), "studentActor")
//send a message to the Student Actor
studentRef ! InitSignal
//Let's wait for a couple of seconds before we shut down the system
Thread.sleep(2000)
//Shut down the ActorSystem.
system.shutdown()
}
[b] 2. STUDENTACTOR响应INITSIGNAL消息并将QUOTEREQUEST消息发送给TEACHERACTOR[/b]
以及
[b] 4. STUDENTACTOR接收到TEACHERACTOR回复的QuoteResponse然后将日志打印到控制台/logger上来[/b]
为什么我把第2和第4点放到一起来讲?因为它太简单了,如果分开讲的话我怕你嫌我啰嗦。
[img]https://raw.githubusercontent.com/arunma/blogimages/master/Akka3/StudentTeacher.png[/img]
那么,第2步——StudentActor接收到DriverApp发过来的InitSingal消息并将QuoteRequest发送给TeacherActor。
def receive = {
case InitSignal=> {
teacherActorRef!QuoteRequest
}
...
...
搞定!
第4步——StudentActor将TeacherActor发过来的消息打印出来。
[img]https://raw.githubusercontent.com/arunma/blogimages/master/Akka3/Student.png[/img]
说到做到:
case QuoteResponse(quoteString) => {
log.info ("Received QuoteResponse from Teacher")
log.info(s"Printing from Student Actor $quoteString")
}
我猜你肯定觉得这很像是伪代码。
那么,完整的StudentActor应该是这样的:
STUDENTACTOR.SCALA
package me.rerun.akkanotes.messaging.requestresponse
import akka.actor.Actor
import akka.actor.ActorLogging
import me.rerun.akkanotes.messaging.protocols.TeacherProtocol._
import me.rerun.akkanotes.messaging.protocols.StudentProtocol._
import akka.actor.Props
import akka.actor.ActorRef
class StudentActor (teacherActorRef:ActorRef) extends Actor with ActorLogging {
def receive = {
case InitSignal=> {
teacherActorRef!QuoteRequest
}
case QuoteResponse(quoteString) => {
log.info ("Received QuoteResponse from Teacher")
log.info(s"Printing from Student Actor $quoteString")
}
}
}
[b] 3. TeacherActor回复QuoteResponse[/b]
这和我们在前面的[url=(http://it.deepinmind.com/akka/2014/10/19/akka-notes-actor-messaging-1.html]fire-n-forget那篇[/url])中看到的代码是类似的。
TeacherActor接收到QuoteRequest消息然后回复一个QuoteResponse。
TEACHERACTOR.SCALA
package me.rerun.akkanotes.messaging.requestresponse
import scala.util.Random
import akka.actor.Actor
import akka.actor.ActorLogging
import akka.actor.actorRef2Scala
import me.rerun.akkanotes.messaging.protocols.TeacherProtocol._
class TeacherActor extends Actor with ActorLogging {
val quotes = List(
"Moderation is for cowards",
"Anything worth doing is worth overdoing",
"The trouble is you think you have time",
"You never gonna know if you never even try")
def receive = {
case QuoteRequest => {
import util.Random
//Get a random Quote from the list and construct a response
val quoteResponse = QuoteResponse(quotes(Random.nextInt(quotes.size)))
//respond back to the Student who is the original sender of QuoteRequest
sender ! quoteResponse
}
}
}
[b] 测试用例[/b]
现在,我们的测试用例会来模拟下DriverApp。由于StudentActor只是打印了个日志消息,我们没法对QuoteResponse本身进行断言,那么我们就看下EventStream中是不是有这条日志消息就好了(就像上回做的那样)
那么,我们的测试用例看起来会是这样的:
"A student" must {
"log a QuoteResponse eventually when an InitSignal is sent to it" in {
import me.rerun.akkanotes.messaging.protocols.StudentProtocol._
val teacherRef = system.actorOf(Props[TeacherActor], "teacherActor")
val studentRef = system.actorOf(Props(new StudentActor(teacherRef)), "studentActor")
EventFilter.info (start="Printing from Student Actor", occurrences=1).intercept{
studentRef!InitSignal
}
}
}
[b] 代码[/b]
项目的完整代码可以从[url=https://github.com/arunma/AkkaMessagingRequestResponse]Github[/url]中进行下载。
在下一篇中,我们将会看到如何在Akka中使用调度器以及如何通过[url=http://kamon.io/]Kamon[/url]来监控你的Akka应用。
原创文章转载请注明出处:[url=http://it.deepinmind.com]http://it.deepinmind.com[/url]
[url=http://rerun.me/2014/10/06/akka-notes-actor-messaging-request-and-response-3/]英文原文链接[/url]