对Spray-can 启动http server的理解

对IO(Http) ? Http.Bind(service, interface = “localhost”, port = 8080)的理解

先上代码,主启动程序及发送Http.Bind的类,放在文件Boo.scala中,与原官方的standalone例子相比,这个是稍微进行了修改。

package com.example

import akka.actor.{ActorRef, Actor, ActorSystem, Props}
import akka.io.{Tcp, IO}
import spray.can.Http
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._

object Boot extends App{

  // we need an ActorSystem to host our application in
  implicit val system = ActorSystem("on-spray-can")

  // create and start our service actor
  val service = system.actorOf(Props[MyServiceActor], "demo-service")

  val server = system.actorOf(Props(new Server(service,system)), "demo-server")
}

class Server(service:ActorRef,implicit val  system:ActorSystem) extends Actor{
  implicit val timeout = Timeout(5.seconds)
  IO(Http) ! Http.Bind(service, interface = "localhost", port = 8088)

  def receive = {
    case x:Tcp.Bound => println("Tcp.Bound="+x)
    case x => println("other messages : "+x)
  }
}

MyServiceActor这个类放在这里

IO(Http)返回一个ActorRef变量,在spray.can.Http中实现, 实际上源代码如下

    val manager = manager = system.actorOf(
    props = Props(new HttpManager(Settings)) withDispatcher Settings.ManagerDispatcher,
    name = "IO-HTTP")
  所以IO(Http)返回的就是这个manager。而这个manager就是在上面代码创建的HttpManager实例。

当这个manager接收到 Http.Bind消息时,就会根据Bind内容及配置创建一个实例去监听端口。代码在spray.can中实现HttpManager的部分。如下

case bind: Http.Bind =>
      val commander = sender()
      listeners :+= context.watch {
        context.actorOf(
          props = Props(newHttpListener(commander, bind, httpSettings)) withDispatcher ListenerDispatcher,
          name = "listener-" + listenerCounter.next())
      }

   这时HttpManager便启动了一个HttpListener实例去监听tcp端口,如果这个HttpListener实例成功绑定了tcp端口,则HttpListener会收到Tcp.Bound消息,这个Tcp.Bound消息也将会发送给上述代码中的server。注意这个Tcp.Bound消息在程序 整个运行过程中只会出现一次。除非你多次向IO(Http)发送Http.Bind消息。
    此时HttpListener实例其实就是一直在监听tcp/ip层的数据, 当外部向服务器进行请求时,HttpListener实例首先会收到一个Tcp.Connected消息,然后马上创建HttpServerConnection实例,这个HttpServerConnection会将tcp层的消息封装成http层的消息。然后再发送给Http.Bind(service, interface = "localhost", port = 8080)中的service。这时service收到的消息其实已经是封闭好了的HttpRequest消息。
      整个过程就是首先创建HttpManager,即IO(Http),然后向这个manager发送Http.Bind消息,创建HttpListener监听tcp层数据,一有外部连接,马上创建HttpServerConnection,该HttpServerConnection会将tcp层的数据进行封装,再以HttpRequest的形式传送给上层应用。

猜你喜欢

转载自blog.csdn.net/innersense/article/details/48918911