ring server(jetty)启动

上次 lein ring server 谈到下面那个核心启动方法

(defn start-server-expr [project]
  `(ring.server.leiningen/serve '~(select-keys project [:ring])))

可以看到 又去引用 ring.server.leiningen serve 方法,那么会正式加载(require)所需的命名空间,及找到 handler、init、destroy函数变量,最后传入standalone/serve 方法,如下:

(ns ring.server.standalone
  "Functions to start a standalone Ring server."
  (:use ring.adapter.jetty
        ring.server.options
        ring.middleware.stacktrace
        ring.middleware.reload
        ring.middleware.refresh
        [clojure.java.browse :only (browse-url)]))

(defn- try-port
  "Try running a server under one port or a list of ports. If a list of ports
  is supplied, try each port until it succeeds or runs out of ports."
  [port run-server]
  (if-not (sequential? port)
    (run-server port)
    (try (run-server (first port))
         (catch java.net.BindException ex
           (if-let [port (next port)]
             (try-port port run-server)
             (throw ex))))))

(defn server-port
  "Get the port the server is listening on."
  [server]
  (-> (.getConnectors server)
      (first)
      (.getPort)))

(defn server-host
  "Get the host the server is bound to."
  [server]
  (-> (.getConnectors server)
      (first)
      (.getHost)
      (or "localhost")))

(defn- open-browser-to [server options]
  (browse-url
   (str "http://" (server-host server) ":" (server-port server) (browser-uri options))))

(defmacro ^{:private true} in-thread
  "Execute the body in a new thread and return the Thread object."
  [& body]
  `(doto (Thread. (fn [] ~@body))
     (.start)))

(defn- add-destroy-hook [server destroy]
  "Add a destroy hook to be executed when the server ends."
  (in-thread
   (try (.join server)
        (finally (if destroy (destroy))))))

(defn- add-stacktraces [handler options]
  (if (stacktraces? options)
    ((or (:stacktrace-middleware options)
         wrap-stacktrace) handler)
    handler))

(defn- add-auto-reload [handler options]
  (if (auto-reload? options)
    (wrap-reload handler {:dirs (reload-paths options)})
    handler))

(defn- add-auto-refresh [handler options]
  (if (:auto-refresh? options)
    (wrap-refresh handler)
    handler))

(defn- add-middleware [handler options]
  (-> handler
      (add-auto-refresh options)
      (add-auto-reload options)
      (add-stacktraces options)))

(defn serve
  "Start a web server to run a handler. Takes the following options:
    :port                  - the port to run the server on
    :join?                 - if true, wait for the server to stop
    :init                  - a function to run before the server starts
    :destroy               - a function to run after the server stops
    :open-browser?         - if true, open a web browser after the server starts
    :browser-uri           - the path to browse to when opening a browser
    :stacktraces?          - if true, display stacktraces when an exception is thrown
    :stacktrace-middleware - a middleware that handles stacktraces
    :auto-reload?          - if true, automatically reload source files
    :reload-paths          - seq of src-paths to reload on change - defaults to [\"src\"]
    :auto-refresh?         - if true, automatically refresh browser when source changes
  If join? is false, a Server object is returned."
  {:arglists '([handler] [handler options])}
  [handler & [{:keys [init destroy join?] :as options}]]
  (let [options (assoc options :join? false)
        destroy (if destroy (memoize destroy))
        handler (add-middleware handler options)]
    (if init (init))
    (if destroy
      (. (Runtime/getRuntime)
         (addShutdownHook (Thread. destroy))))
    (try-port (port options)
      (fn [port]
        (let [options (merge {:port port} options)
              server  (run-jetty handler options)
              thread  (add-destroy-hook server destroy)]
          (println "Started server on port" (server-port server))
          (if (open-browser? options)
            (open-browser-to server options))
          (if join?
            (.join thread))
          server)))))

可以看到首先初始化、Runtime挂上结束回调函数(包括下面的,add-destroy-hook 也是等待(join)server 线程结束回调)。(run-jetty handler options)方法是没有被block的 ,因为options里的赋了 :join? false,目的为了主线程得到返回实例化的server之后启动浏览器,然后再挂起阻塞(join)。

至此 所有的运行都交由ring来管理,run-jetty 方法是其jetty的适配器;重载等方法也用的是其中间件reload、refresh、stacktrace。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>