消息

我们只是让QuoteRequest到ActorRef去但是我们根本没见过消息类!

它是这样的:
(一个最佳实践是把你的消息类包装在一个完整的对象里以利于更好的组织)

TeacherProtocol

package me.rerun.akkanotes.messaging.protocols

object TeacherProtocol{

  case class QuoteRequest()
  case class QuoteResponse(quoteString:String)

}

就像你知道的,QuoteRequest是用来发给TeacherActor的。Actor应该响应一个QuoteResponse回来。

分发者DISPATCHER和邮箱MAILBOX

ActorRef将消息处理功能委托给Dispatcher。在底层实现中,当我们创建一个ActorSystemActorRef的时候,一个Dispatcher和一个MailBox也被创建出来了。让我们看下他们。
图片描述

邮箱MailBox

Actor有一个MailBox(稍后我们会看到一个特例)。在我们的例子里,每个老师都有一个邮箱(mailbox)。老师需要检查邮箱(mailbox)并且处理消息。在Actor的世界里,是另一种样子-邮箱(mailbox),当它有机会它会使用Actor来完成它的工作。

邮箱维护一个先入先出的队列来保存和处理消息- 跟我们常规的收件箱有点不一样,常规的收件箱总是最新的邮件在最上面。

现在,分发者 dispatcher

分发者做的事很有趣。表面上看,分发者只是从ActorRef拿到消息然后将消息发给MailBox。但是在这个场景里有个很神奇的事情:

分发者包装了ExecutorService(ForkJoinPool或者ThreadPoolExecutor)。 它用这个ExecutorService来执行MailBox

看一下这个Dispathcer里的片断:

protected[akka] override def registerForExecution(mbox: Mailbox, ...): Boolean = {  
    ...
    try {
        executorService execute mbox
    ...
}

什么?你说你执行MailBox?

是的。我们已经看到了MailBox将所有消息维护在一个队列里。当Executor运行MailBox时,MailBox必须是一个线程(Thread)。就是这样,这就是MailBox的声明和构造函数。

这里是Mailbox的签名

private[akka] abstract class Mailbox(val messageQueue: MessageQueue) extends SystemMessageQueue with Runnable

TEACHER ACTOR

图片描述

MailBox,当它的run方法被调用时,从队列里获取一条消息并把它发给Actor来处理。

在你将消息告知(tell)ActorRef的时候一定会调用到目标Actor的receive方法。

这里的TeacherActor是个基本类,维护一个格言列表(List)并自带能处理消息的方法receive

看下这里:

TeacherActor.scala

package me.rerun.akkanotes.messaging.actormsg1

import scala.util.Random

import akka.actor.Actor  
import me.rerun.akkanotes.messaging.protocols.TeacherProtocol._

/*
 * Your Teacher Actor class. 
 * 
 * The class could use refinement by way of  
 * using ActorLogging which uses the EventBus of the Actor framework
 * instead of the plain old System out
 * 
 */

class TeacherActor extends Actor {

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

      println (quoteResponse)

    }

  }

}

TeacherActor只接受一种消息格式-QuoteRequest(实际上,这个让模式匹配默认case的方式是个好实践,但这儿还是有个有趣的故事)

receive方法做的所有事是

  1. 根据模式匹配QuoteRequest

  2. 从格言的静态列表(list)中随机选取一个格言

  3. 构造一个QuoteResponse

  4. 将QuoteResponse打印到控制台

代码

完整项目可以在github下载。


文章来自微信平台「麦芽面包」,微信号「darkjune_think」。转载请注明。
图片描述


祝坤荣
1k 声望1.5k 粉丝

科幻影迷,书虫,硬核玩家,译者


引用和评论

0 条评论