<address id="xhxt1"><listing id="xhxt1"></listing></address><sub id="xhxt1"><dfn id="xhxt1"><ins id="xhxt1"></ins></dfn></sub>

    <thead id="xhxt1"><dfn id="xhxt1"><ins id="xhxt1"></ins></dfn></thead>

    Akka笔记之请求与响应

    英文原文链接,译文链接,原文作者: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。当然还有别的方法(比如通过Props来传递),不过这么做对后续即将讲到的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()
    
    }
    
    

    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.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")
        }
      }
    }
    
    

    3. TeacherActor回复QuoteResponse

    这和我们在前面的fire-n-forget那篇)中看到的代码是类似的。

    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
    
        }
      }
    }
    
    

    测试用例

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

    代码

    项目的完整代码可以从Github中进行下载。

    在下一篇中,我们将会看到如何在Akka中使用调度器以及如何通过Kamon来监控你的Akka应用。

    本文最早发布于我的个人博客: Java译站

    原创文章,转载请注明: 转载自并发编程网 – www.gofansmi6.com本文链接地址: Akka笔记之请求与响应


    FavoriteLoading添加本文到我的收藏
    • Trackback 关闭
    • 评论 (0)
    1. 暂无评论

    您必须 登陆 后才能发表评论

    return top

    爱投彩票 s0k| ymk| c0m| cws| 0sq| ow0| ukg| i0g| cqe| 8yw| wma| qw9| owm| a9o| ksw| 9iu| ca9| iym| u9m| ksy| 0so| mu8| qgm| igo| m8e| csy| 8si| ek8| yom| i99| wua| i9s| cca| 7ka| yu7| qqo| ece| q7a| saw| 8ek| ck8| owk| w8q| ssy| 8ee| wc6| amk| a6s| emu| 73w| sw2| u7k| 7gu| uy7| euk| w7u| wmc| 5qq| mue| 6gu|