2012-05-16 25 views
2

我試圖找到一個配置服務器端Java應用程序的解決方案,以便系統的不同用戶與系統進行交互,就像配置不同(Multitenancy)一樣。例如,當我的應用程序處理來自user1的請求時,我希望我的應用程序在Klingon中響應,但是對於所有其他用戶,我希望它以英語回覆。 (我選擇了一個故意荒謬的例子,以避免具體情況:重要的是我希望應用程序對不同請求的行爲不同)。針對Java的多租戶/條件配置存在哪些庫?

理想的情況下有一個通用的解決方案(即一個可以讓我 用戶特定的覆蓋增加我的配置中的任何部分,而無需更改代碼)。

我有一個看的Apache Commons Configuration也具有built in support for multitenant configuration,但據我所知,這是通過將一些基本的配置一些一套覆蓋的完成。這意味着我有一個配置指定:

application.lang=english 

,並說user1.properties覆蓋文件:

application.lang=klingon 

可惜這對我們的支持團隊容易得多,如果他們能看到一個所有相關配置以指定內聯方式指定覆蓋,而不是分開文件基地覆蓋

我認爲Commons Config的多租戶+類似於Velocity template的一些組合可以描述底層配置中的條件元素,這就是我所瞄準的類型 - Commons Config,用於輕鬆與我的配置和Velocity進行交互,描述了任何覆蓋,在一個單一的配置,如:

#if ($user=="user1") 
application.lang=klingon 
#else 
application.lang=english 
#end 

有什麼解決辦法是使用這種問題的人呢?

+0

國際海事組織你的速度的例子會更難處理。通常人們使用應用程序/前端來編輯多個配置文件,如資源/翻譯文件。在配置工具上只消耗很少的能量,後端並不重要。 –

+0

@Dave但是如果我選擇使用這個作爲我的後端,我仍然需要這樣寫_tool_? – bacar

回答

0

通常,用戶配置文件將進入數據庫,用戶必須使用登錄名打開會話。用戶名可以進入HTTPSession(= Cookies),並且在每次請求時服務器都將獲得用戶名,並且可以從DB讀取配置文件。舒爾,數據庫可以是一些配置文件,如joe.properties,jim.properties,admin.properties等。

+1

這不是一個HTTP服務器應用程序 - 這個答案並沒有真正解決基於條件邏輯覆蓋默認值的概念 - 你似乎只是建議加載一個完全獨立的屬性文件。 – bacar

3

編碼每個服務器操作是否可接受,如下所示?

void op1(String username, ...) 
{ 
    String userScope = getConfigurationScopeForUser(username); 
    String language = cfg.lookupString(userScope, "language"); 
    int fontSize = cfg.lookupInt(userScope, "font_size"); 
    ... // business logic expressed in terms of language and fontSize 
} 

(以上僞代碼假定一個用戶的名稱作爲參數傳遞,但是可能通過其它機制通過它,例如,線程局部存儲器)。

如果上述是可以接受的,那麼Config4*可以滿足您的要求。使用CONFIG4 *,在上述僞碼中使用的getConfigurationScopeForUser()方法可以被實現爲如下(假定cfg是已經通過解析配置文件被預先初始化的配置對象):

String getConfigurationScopeForUser(String username) 
{ 
    if (cfg.type("user", username) == Configuration.CFG_SCOPE) { 
     return Configuration.mergeNames("user", username); 
    } else { 
     return "user.default"; 
    } 

} 

下面是一個示例配置文件與上面的工作。大多數用戶從「用戶」獲得他們的配置。默認的「範圍,但瑪麗和約翰有一些自己的這些默認值覆蓋:

user.default { 
    language = "English"; 
    font_size = "12"; 
    # ... many other configuration settings 
} 

user.John { 
    @copyFrom "user.default"; 
    language = "Klingon"; # override a default value 
} 

user.Mary { 
    @copyFrom "user.default"; 
    font_size = "18"; # override a default value 
} 

如果喜歡它上面的聲音可能會滿足你的需求,那麼我建議你閱讀第2和第3」獲得入門指南「,以充分理解Config4 *語法和API,以便能夠根據您的需求確認/駁斥Config4 *的適用性。您可以在Config4 * website上找到該文檔。

聲明:我是Config4 *的維護者。

編輯:我提供更多的附件ls迴應巴卡的評論。

我沒有把Config4 *放在Maven倉庫中。但是,使用捆綁的Ant構建文件構建Config4 *是微不足道的,因爲Config4 * 而不是對第三方庫有任何依賴關係。

在服務器應用程序中使用* CONFIG4到CONFIG4 *另一種方法(由巴卡爾評論提示)是如下...

實現每個服務器的操作如以下僞代碼:

void op1(String username, ...) 
{ 
    Configuration cfg = getConfigurationForUser(username); 
    String language = cfg.lookupString("settings", "language"); 
    int fontSize = cfg.lookupInt("settings", "font_size"); 
    ... // business logic expressed in terms of language and fontSize 
} 

如圖以下僞碼上面所用的方法getConfigurationForUser()可以實現:

HashMap<String,Configuration> map = new HashMap<String,Configuration>(); 

synchronized String getConfigurationForUser(String username) 
{ 
    Configuration cfg = map.get(username); 
    if (cfg == null) { 
     // Create a config object tailored for the user & add to the map 
     cfg = Configuration.create(); 
     cfg.insertString("", "user", username); // in global scope 
     cfg.parse("/path/to/file.cfg"); 
     map.put(username, cfg); 
    } 
    return cfg;  
} 

下面是一個示例configuratio n文件與上面的工作。是

user ?= ""; // will be set via insertString() 
settings { 
    @if (user @in ["John", "Sam", "Jane"]) { 
     language = "Klingon"; 
    } @else { 
     language = "English"; 
    } 
    @if (user == "Mary") { 
     font_size = "12"; 
    } @else { 
     font_size = "10"; 
    } 
    ... # many other configuration settings 
} 

我有兩種方法的主要意見如下:

  1. 第一種方法(包含大量的變量和作用域一個Configuration對象)可能使用略少的內存比第二種方法(許多Configuration對象,每個對象具有少量變量)。但我的猜測是,任何一種方法的內存使用量都將以KB或幾十KB來衡量,與您的服務器應用程序的整體內存佔用量相比,這將是微不足道的。

  2. 我更喜歡第一種方法,因爲一個Configuration對象僅初始化一次,然後通過只讀lookup()樣式的操作對其進行訪問。這意味着即使您的服務器應用程序是多線程的,您也不必擔心同步對象的訪問權限。相反,如果您的服務器應用程序是多線程的,則第二種方法要求您同步對HashMap的訪問。

  3. lookup()樣式操作的開銷按照例如納秒或微秒的順序進行,而解析配置文件的開銷按照例如毫秒或幾十毫秒的順序(取決於文件大小)。第一種方法只執行一次相對昂貴的配置文件解析,並在應用程序的初始化中完成。相比之下,第二種方法執行相對昂貴的配置文件「N」次解析(每個「N」個用戶一次),並且在服務器處理來自客戶端的請求時發生重複費用。這種性能問題可能會或可能不會成爲您應用程序的問題。

  4. 我認爲易用性比易用性更重要。所以,如果你覺得第二種方法會更容易維護配置文件,那麼我建議你使用這種方法。

  5. 在第二種方法中,你可能想知道爲什麼我把大部分的變量的命名範圍(settings),而不是與「注入」 user變量一起在全球範圍內。我這樣做是因爲你的問題範圍之外的原因:從應用程序可見變量中分離「注入」變量使得更容易對應用程序可見變量執行模式驗證。

+0

很酷,謝謝。 +1的詳細答案。我在其他的一篇文章中遇到過Config4 * - 我不太清楚如何讓這個工作正常。我不相信我能得到速度模板給予我的表現力(例如,如果我想在一個更大的結構中只改變一個子元素),但我會玩。有沒有配置4 *的Maven回購? – bacar

+0

查看了一下,它讓我感到注入了一個名爲'user'的變量(例如'cfg.insertString(「user」,「John」)'),然後使用了@if(user ==「John」){ language =「Klingon」; } @else {language =「English」; }'可能更容易管理並獲得我追求的表現力。 @Ciaran - 關於遵循這種方法的觀點? – bacar

+0

@bacar:我已經編輯了我的回答以迴應您的意見。 –