2013-11-04 125 views
13

如何將狀態最方便地注入環處理程序(不使用全局變量)?將狀態作爲參數傳遞給環處理程序?

下面是一個例子:

(defroutes main-routes 
    (GET "/api/fu" [] (rest-of-the-app the-state))) 

(def app 
    (-> (handler/api main-routes))) 

我想獲得the-state進入的Compojure處理程序main-routes。狀態可能是這樣用創建的地圖:

(defn create-app-state [] 
    {:db (connect-to-db) 
    :log (create-log)}) 

在非環應用程序,我將創建一個主功能狀態,並開始注射,或它的一部分,作爲函數參數的不同組件應用程序。

可以使用ring的:init函數做類似的事情,而不使用全局變量?

+0

您是否在尋找每個會話狀態或全局狀態? – astine

+0

global - 與init:和destroy相同的生存期 – 4ZM

回答

20

我見過這樣做了幾種方法。第一種是使用中間件將狀態作爲請求映射中的新密鑰注入。例如:

(defroutes main-routes 
    (GET "/api/fu" [:as request] 
    (rest-of-the-app (:app-state request)))) 

(defn app-middleware [f state] 
    (fn [request] 
    (f (assoc request :app-state state)))) 

(def app 
    (-> main-routes 
     (app-middleware (create-app-state)) 
     handler/api)) 

另一種方法是更換呼叫defroutes,它在幕後將創建一個處理程序,並把它分配給一個變種,與將接受一些狀態,然後制定的路線的功能,注射狀態作爲參數傳遞給路由定義中的函數調用:

(defn app-routes [the-state] 
    (compojure.core/routes 
    (GET "/api/fu" [] (rest-of-the-app the-state)))) 

(def app 
    (-> (create-app-state) 
     app-routes 
     api/handler)) 

如果可以選擇,我可能會用第二種方法去。

+1

謝謝!第二種方法似乎很合適。第一個人覺得有點黑客。 – 4ZM

-1

執行此操作的「正確」方法是使用動態綁定的變量。你定義一個變種有:

(def ^:dynamic some-state nil) 

,然後創建結合了var每個處理程序調用一些環中間件:

(defn wrap-some-state-middleware [handler some-state-value] 
    (fn [request] 
    (bind [some-state some-state-value] 
     (handler request)))) 

你會用它來注入依賴在你的「主使用這'功能在哪裏啓動服務器:

(def app (-> handler 
      (wrap-some-state-middleware {:db ... :log ...}))) 
+0

你將會使用動態進入很多狀態管理。這可能會導致一些嚴重的問題。 – Virmundi

相關問題