Component

簡介

Component用于管理擁有運行期狀態(tài)的組件的生命周期和依賴關(guān)系。

創(chuàng)建組件

一個實現(xiàn)了Lifecycle協(xié)議的record就是一個組件。

(defrecord Database [host port connection]
  ;; 實現(xiàn)Lifecycle協(xié)議
  component/Lifecycle

  (start [component]
    (println ";; Starting database")
    ;; 在start方法初始化組件并啟動。例如,連接到數(shù)據(jù)庫,創(chuàng)建線程池等。
    (let [conn (connect-to-database host port)]
      ;; 返回更新后的組件,附帶了運行時狀態(tài)。
      (assoc component :connection conn)))

  (stop [component]
    (println ";; Stopping database")
    ;; 在stop方法停止組件,并釋放組件所獲取的外部資源。
    (.close connection)
    ;; 返回組件,修改組件的狀態(tài)是可選的。
    (assoc component :connection nil)))

可以定義一個創(chuàng)建函數(shù)初始化基本配置,保留運行期配置為空。

(defn new-database [host port]
  (map->Database {:host host :port port}))

使用組件

需要使用組件的函數(shù),傳入一個組件實例作為參數(shù)。

(defn get-user [database username]
  (execute-query (:connection database)
    "SELECT * FROM users WHERE username = ?"
    username))

組件依賴

如果a組件依賴于b組件,在a組件中定義一個屬性用于存放所依賴的b組件。Component庫自動注入所依賴的組件。

不要在構(gòu)造函數(shù)中傳入依賴的組件。

(defrecord ExampleComponent [options cache database scheduler]
  component/Lifecycle

  (start [this]
    (println ";; Starting ExampleComponent")
    ;; 在start方法中,該組件的依賴組件都已經(jīng)啟動完成,并且注入進來了,可以直接使用。
    (assoc this :admin (get-user database "admin")))

  (stop [this]
    (println ";; Stopping ExampleComponent")
    ;; 在stop方法中,該組件的依賴組件仍在啟動狀態(tài),直到當(dāng)前組件停止后,依賴組件才會停止。
    this))

System

System用于啟動和停止其他組件,以及負(fù)責(zé)注入組件依賴。創(chuàng)建system最簡單的方式是使用system-map函數(shù),傳入一組key和組件實例作為參數(shù)。使用using函數(shù)指定依賴關(guān)系。

(component/system-map
  :db (new-database host port)
  :scheduler (new-scheduler)
  :app (component/using
         (example-component config-options)
         {:database  :db
          :scheduler :scheduler}))

如果鍵名相同,可以使用vector指定依賴關(guān)系。

(component/system-map
  :database (new-database host port)
  :scheduler (new-scheduler)
  :app (component/using
         (example-component config-options)
         [:database :scheduler]))

system本身也是組件,system-map輸出的system實例同樣實現(xiàn)了Lifecycle協(xié)議,并負(fù)責(zé)其他組件的啟動和停止。

可以使用system-using一次性指定整個system的依賴關(guān)系。

(-> (component/system-map
      :config-options config-options
      :db (new-database host port)
      :sched (new-scheduler)
      :app (example-component config-options))
    (component/system-using
      {:app {:database  :db
             :scheduler :sched}}))

Reload

參考這個工作流。在開發(fā)環(huán)境中:

(ns user
  (:require [com.stuartsierra.component :as component]
            [clojure.tools.namespace.repl :refer (refresh)]
            [examples :as app]))

(def system nil)

(defn init []
  (alter-var-root #'system
                  (constantly (app/example-system {:host "dbhost.com" :port 123}))))

(defn start []
  (alter-var-root #'system component/start))

(defn stop []
  (alter-var-root #'system
                  (fn [s] (when s (component/stop s)))))

(defn go []
  (init)
  (start))

(defn reset []
  (stop)
  (refresh :after 'user/go))

生產(chǎn)環(huán)境

(ns com.example.application.main
  (:gen-class)
  (:require [com.stuartsierra.component :as component]
            [examples :as app]))

(defn -main [& args]
  (let [[host port] args]
    (component/start
      (app/example-system {:host host :port port}))))
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容