Akka-Http DSL 发生了什么?
What Happend In Akka-Http DSL?
最近刚接触akka,在学习akka-http的时候,被RestAPI DSL所吸引,这里有一段代码:
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model._
import akka.http.scaladsl.server.Directives._
import akka.stream.ActorMaterializer
import scala.io.StdIn
object WebServer {
def main(args: Array[String]) {
implicit val system = ActorSystem("my-system")
implicit val materializer = ActorMaterializer()
// needed for the future flatMap/onComplete in the end
implicit val executionContext = system.dispatcher
val route =
path("hello") {
get {
complete("Say hello to akka-http")
}
}
val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
StdIn.readLine() // let it run until user presses return
bindingFuture
.flatMap(_.unbind()) // trigger unbinding from the port
.onComplete(_ => system.terminate()) // and shutdown when done
}
}
我无法理解的是val route = path("hello") {....}
。我知道“path”方法将 return 一个指令,“get”方法也是一个指令,但我不明白指令如何通过大括号“{}”“嵌入”到另一个指令中.
我知道,肯定有一些隐式转换,通过调试,我看到,应用了以下隐式转换:akka.http.scaladsl.server.Directive#addByNameNullaryApply
implicit def addByNameNullaryApply(directive: Directive0): (⇒ Route) ⇒ Route =
r ⇒ directive.tapply(_ ⇒ r)
谁能给我解释一下:这个隐式转换是如何被选择和发生的? apply 和 tapply 尝试做什么?非常感谢!
第一个:
val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
等于:
val bindingFuture = Http().bindAndHandle(Route.handlerFlow(route), "localhost", 8080)
Route.handlerFlow
方法用于将Route
转换为Flow[HttpRequest, HttpResponse, NotUsed]
,我们看到bindAndHandle
接受handler
类型是:Flow[HttpRequest, HttpResponse, Any]
隐式转换route
到Flow[HttpRequest, HttpResponse, NotUsed]
是由RouteResult.route2HandlerFlow
实现的。这由 Directives
扩展并与 import akka.http.scaladsl.server.Directives._
一起使用。
所以当你导入指令时,你导入这个隐式转换。
对于addByNameNullaryApply
,我们可以重写如下代码:
...
val path1: Directive0 = path("hello")
val contextToEventualResult: Route = get(complete("Say hello to akka-http"))
val route: Route = path1.apply(contextToEventualResult)
...
如我们所见,对于 path1.apply(contextToEventualResult)
,它正在调用 高阶函数 并应用 contextToEventualResult
参数。但是 path1
的类型是 Directive0
,所以:
implicit def addByNameNullaryApply(directive: Directive0): (⇒ Route) ⇒ Route
用于将 Directive0
类型转换为 高阶函数 ,类型为:(⇒ Route) ⇒ Route
.
最近刚接触akka,在学习akka-http的时候,被RestAPI DSL所吸引,这里有一段代码:
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model._
import akka.http.scaladsl.server.Directives._
import akka.stream.ActorMaterializer
import scala.io.StdIn
object WebServer {
def main(args: Array[String]) {
implicit val system = ActorSystem("my-system")
implicit val materializer = ActorMaterializer()
// needed for the future flatMap/onComplete in the end
implicit val executionContext = system.dispatcher
val route =
path("hello") {
get {
complete("Say hello to akka-http")
}
}
val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
StdIn.readLine() // let it run until user presses return
bindingFuture
.flatMap(_.unbind()) // trigger unbinding from the port
.onComplete(_ => system.terminate()) // and shutdown when done
}
}
我无法理解的是val route = path("hello") {....}
。我知道“path”方法将 return 一个指令,“get”方法也是一个指令,但我不明白指令如何通过大括号“{}”“嵌入”到另一个指令中.
我知道,肯定有一些隐式转换,通过调试,我看到,应用了以下隐式转换:akka.http.scaladsl.server.Directive#addByNameNullaryApply
implicit def addByNameNullaryApply(directive: Directive0): (⇒ Route) ⇒ Route =
r ⇒ directive.tapply(_ ⇒ r)
谁能给我解释一下:这个隐式转换是如何被选择和发生的? apply 和 tapply 尝试做什么?非常感谢!
第一个:
val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
等于:
val bindingFuture = Http().bindAndHandle(Route.handlerFlow(route), "localhost", 8080)
Route.handlerFlow
方法用于将Route
转换为Flow[HttpRequest, HttpResponse, NotUsed]
,我们看到bindAndHandle
接受handler
类型是:Flow[HttpRequest, HttpResponse, Any]
隐式转换route
到Flow[HttpRequest, HttpResponse, NotUsed]
是由RouteResult.route2HandlerFlow
实现的。这由 Directives
扩展并与 import akka.http.scaladsl.server.Directives._
一起使用。
所以当你导入指令时,你导入这个隐式转换。
对于addByNameNullaryApply
,我们可以重写如下代码:
...
val path1: Directive0 = path("hello")
val contextToEventualResult: Route = get(complete("Say hello to akka-http"))
val route: Route = path1.apply(contextToEventualResult)
...
如我们所见,对于 path1.apply(contextToEventualResult)
,它正在调用 高阶函数 并应用 contextToEventualResult
参数。但是 path1
的类型是 Directive0
,所以:
implicit def addByNameNullaryApply(directive: Directive0): (⇒ Route) ⇒ Route
用于将 Directive0
类型转换为 高阶函数 ,类型为:(⇒ Route) ⇒ Route
.