Scala — Как проходит путь вызова спрея (отладка кода спрея)

Я новичок в Scala, Spray и функциональном программировании. И мне так грустно, что я до сих пор не могу понять базовый пример Spray RestAPI.

Я написал программу в соответствии с инструкциями, приведенными в этом сообщении в блоге. http://www.smartjava.org/content/first-steps-rest-spray-and-scala

И моя функция Route выглядит следующим образом.

  val aSimpleRoute =
    path("path1") {
      println("in path path1..")
      put {
        println("in path path1/put..")
        respondWithMediaType(MediaTypes.`text/html`) {
          complete {
            <h1>in path path1/put..</h1>
          }
        }
      } ~ get {
        println("in path path1/get..")
        respondWithMediaType(MediaTypes.`application/json`) {
          complete {
            <h1>in path path1/get..</h1>
          }
        }
      }
    } ~
  path("path2") {
    println("in path path2..")
    get {
      println("in path path2/get..")
      respondWithMediaType(MediaTypes.`application/json`) {
        complete {
          <h1>in path path2/get..</h1>
        }
      }
    } ~ post {
      println("in path path2/post..")
      respondWithMediaType(MediaTypes.`application/json`) {
        complete {
          <h1>in path path2/post..</h1>
        }
      }
    }
  }

Все работает так, как ожидалось. Но моя проблема в том, что когда моя программа запускается, она запускает функцию приема. Посмотрите мой вывод println при запуске программы (до того, как она обработает любой http-запрос)

in path path1..
in path path1/put..
in path path1/get..
in path path2..
in path path2/get..
in path path2/post..
[INFO] [09/14/2015 12:56:01.364] [on-spray-can-akka.actor.default-dispatcher-4] [akka://on-spray-can/user/IO-HTTP/listener-0] Bound to localhost/127.0.0.1:8080

Вот и я не могу понять, почему программа заходит во все возможные пути вызова, когда она запускалась. Кроме того, ни один из этих println не достигается при получении HTTP-запроса.

Кто-нибудь может объяснить, почему?


person Janaka Priyadarshana    schedule 14.09.2015    source источник


Ответы (2)


Вы можете найти объяснение здесь: Общие сведения об извлечении

Короче говоря, нелистовые и непараметризованные (без извлечения) директивы выполняются только один раз при построении маршрута. Директива Leaf (например, complete) выполняется только в том случае, если запрос попадает на маршрут директивы. Параметризованные директивы (и все, что внутри них) выполняются по запросу (поскольку извлекаемый параметр каждый раз разный) - даже если сама директива идет после директивы, которая уже приняла этот запрос.

В вашем случае у вас есть println внутри нелистовых и непараметризованных директив, поэтому они выполнялись только один раз при инициализации. Если вы хотите, чтобы они выполнялись по приемлемому запросу, просто переместите их внутрь complete:

val aSimpleRoute =
  path("path1") {
    put {     
      respondWithMediaType(MediaTypes.`text/html`) {
        complete {
          println("in path path1/put..")
          <h1>in path path1/put..</h1>
        }
      }
    } ~ get {
      respondWithMediaType(MediaTypes.`application/json`) {
        complete {
          println("in path path1/get..")
          <h1>in path path1/get..</h1>
        }
      }
    }
  } ~
  path("path2") {
    get {    
      respondWithMediaType(MediaTypes.`application/json`) {
        complete {
          println("in path path2/get..")
          <h1>in path path2/get..</h1>
        }
      }
    } ~ post {
      respondWithMediaType(MediaTypes.`application/json`) {
        complete {
          println("in path path2/post..")
          <h1>in path path2/post..</h1>
        }
    }
  }

Обсуждение проходит здесь

person dk14    schedule 14.09.2015
comment
Спасибо за точный ответ на мой вопрос. Это поведение специфично для спрея или вообще для Scala?? - person Janaka Priyadarshana; 18.09.2015
comment
это спрей-специфический; однако он использует функции языка scala, такие как ленивые вычисления. Например, тело функции complete приходит как параметр call-by-name, что означает, что это (тело) практически является функцией с нулевыми параметрами, поэтому ее выполнение может быть задержано. Вот почему println внутри complete действует иначе. - person dk14; 18.09.2015

Ну, вы использовали val для объявления маршрутов распыления, это нормальное поведение, потому что когда вы запускаете свою программу, Scala инициализирует vals, если вы поставите lazy val вместо val, вы увидите, что вы получите печать, когда будете использовать этот val явно.

Например:

    val a = {
        println("val a initialization")
        "val a initialization"
      }
 
   lazy val b = {
        println("using of val b")
        "using of val b"
      }
    
      println("use of Val a " + a)
    
      println("use of val b  " + b)

Результат:

val a initialization
use of Val a val a initialization
using of val b
use of val b  using of val b
person Dmitri    schedule 14.09.2015