博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Akka笔记之请求与响应
阅读量:6814 次
发布时间:2019-06-26

本文共 5122 字,大约阅读时间需要 17 分钟。

,,原文作者:Arun Manivannan ,译者:有孚

前面我们讲到了Actor的,并看到了如何发送一条fire-n-forget消息(也就是说,消息发送给Actor后我们就不管了,不从Actor那接收响应)。

技术上来讲,消息发送给Actor就是希望能有副作用的。设计上便是如此。目标Actor可以不做响应,也可以做如下两件事情——

1. 给发送方回复一条响应(在本例中,TeacherActor会将一句名言回复给StudentActor)

2. 将响应转发给其它的目标受众Actor,后者也可以进行响应/转发/产生副作用。Router和Supervisor就是这种情况。(很快我们就会看到)

请求及响应

本文中我们只关注第一点——请求及响应周期。

image

这张图说明了我们这次要做的事情。为了简单点,图中我并没有画出ActorSystem, Dispatcher以及Mailbox。

1. DriverApp将一条InitSignal消息发送给StudentActor。

2. StudentActor响应InitSignal消息并将一条QuoteRequest消息发送到TeacherActor。
3. 正如前面所说的那样,TeacherActor会回复一个QuoteResponse。
4. StudentActor将日志打印到控制台或者logger里。

同样的,我们会写一个测试用例来验证下它。

现在我们来仔细地分析下这四个步骤:

1. DRIVERAPP将一条INITSIGNAL消息发送给STUDENTACTOR

image

现在你应该能猜到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。当然还有别的方法(比如通过来传递),不过这么做对后续即将讲到的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.requestresponseimport akka.actor.ActorSystemimport akka.actor.Propsimport me.rerun.akkanotes.messaging.protocols.StudentProtocol._import akka.actor.ActorRefobject 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()}

2. STUDENTACTOR响应INITSIGNAL消息并将QUOTEREQUEST消息发送给TEACHERACTOR

以及

4. STUDENTACTOR接收到TEACHERACTOR回复的QuoteResponse然后将日志打印到控制台/logger上来

为什么我把第2和第4点放到一起来讲?因为它太简单了,如果分开讲的话我怕你嫌我啰嗦。

image

那么,第2步——StudentActor接收到DriverApp发过来的InitSingal消息并将QuoteRequest发送给TeacherActor。

def receive = {    case InitSignal=> {          teacherActorRef!QuoteRequest    }    ...    ...

搞定!

第4步——StudentActor将TeacherActor发过来的消息打印出来。

image

说到做到:

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.requestresponseimport akka.actor.Actorimport akka.actor.ActorLoggingimport me.rerun.akkanotes.messaging.protocols.TeacherProtocol._import me.rerun.akkanotes.messaging.protocols.StudentProtocol._import akka.actor.Propsimport akka.actor.ActorRefclass 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")    }  }}

3. TeacherActor回复QuoteResponse

这和我们在前面的)中看到的代码是类似的。

TeacherActor接收到QuoteRequest消息然后回复一个QuoteResponse。

TEACHERACTOR.SCALA

package me.rerun.akkanotes.messaging.requestresponseimport scala.util.Randomimport akka.actor.Actorimport akka.actor.ActorLoggingimport akka.actor.actorRef2Scalaimport 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    }  }}

测试用例

现在,我们的测试用例会来模拟下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      }    }  }

转载地址:http://qxkzl.baihongyu.com/

你可能感兴趣的文章
js中括号用于自执行测试
查看>>
svn迁移至git
查看>>
springMVC 表单联动处理 点击radio联动改变select选项
查看>>
Nagios开发自定义插件check_netstat
查看>>
浅谈@RequestMapping @ResponseBody 和 @RequestBody 注解的用法与区别
查看>>
ssh 公钥 密钥
查看>>
c#设计模式-单例模式
查看>>
Ehcache web cahce 缓存改良版
查看>>
F5集群配置公共irule,解决X-Frame-Options漏洞及host头漏洞
查看>>
mysql 创建日期列之timestamp
查看>>
VMM系列之使用VMM服务器构建 Hyper-V主机(4)
查看>>
详测 Generics Collections TList (7): Items、Contains
查看>>
配置FTP服务器(2) 本地用户下载和上传
查看>>
多线程编程(11) - 多线程同步之 Mutex (互斥对象)[续]
查看>>
【Java每日一题】20161214
查看>>
requireJs 模块化简陋版本
查看>>
我的友情链接
查看>>
How to upgrade vim to version 8 on CentOS 7
查看>>
xcode pod 报import 找不到 pods的支持问题解决方法之一
查看>>
nginx配置让任何文件在浏览器中显示文本text/plain
查看>>