簡體   English   中英

存儲和訪問Java應用程序數據的最佳方法

[英]Best approach storing and accessing Java application data

我正處於一個大規模重構項目的中間,代碼有一個5000行主類,它被注入到所有內容中,存儲了所有內容並擁有所有常用代碼。

我不是分析和設計方面的專家,但是我已經盡可能地分離了一些東西,並且通過重構依賴於主類的類來使用我創建的新類,我大約80%。

有些類型的數據在應用程序啟動時初始化,並且在應用程序的整個生命周期中都可以訪問。 例如,有一個Config類,它包含數百個參數。

我采用的方法是創建幾個單例,其中最重要的兩個是GUIData和ClientData。 GUIData包含對應用程序主機的引用,clientdata維護對配置和其他類似類的引用。

這允許我從代碼中的任何地方調用ClientData.getInstance()。getConfig()。getParam(“param”),但我不認為這是最好的方法。

我考慮了單個靜態類而不是包含類實例的這些數據單例,但是一些類確實需要構造函數。

我一直在谷歌搜索和關閉一個星期試圖找到一個更好的方法來做到這一點,但不知怎的,我總是最終在談論數據庫緩存的線程

不可變(配置)實例提供“線程安全的應用程序范圍的數據訪問”。 Typesafe的配置 (正如Brian Kent的評論中所建議的那樣)正是如此。 請注意,這不涉及靜態類或單例。 靜態類和單身可能現在可以滿足您的需求,但它們將來可能會令人煩惱。 它們可以很方便,但嘗試限制它們的使用。

在讀取和解析配置數據之后,必須進行初始化。 它通常在應用程序啟動時完成,然后啟動其他處理線程。 初始化必須盡可能多地驗證配置數據,以便快速失敗並在配置數據不佳時終止程序。

將大量配置數據捆綁在一起可以創建“隱藏的通信線”。 例如,您更新一個值並且應用程序失敗,因為它還需要更新其他值。 將所有配置數據放在一個文件中並從那里加載它是完美的,但是您的應用程序(具有數百個配置選項)應該將應用程序的不同部分使用的組中的配置數據分開。 這可以改善隔離,幫助進行單元測試,並且可以在將來更改應用程序,而不會產生太多令人討厭的意外。

有兩種方法可以使用一組配置數據:

  1. 從對象內部調用單例Settings.getInstance().getConfigForThisModule()
  2. 通過構造函數或通過setConfig(ConfigForThisModule config)提供使用配置數據和配置數據的每個對象。

第一種方法取決於不調用Settings.getInstance().getConfigForACompletelyUnrelatedModule()的約定,這可能是一個弱點。 第二種方法更符合“依賴注入”,可能更具未來性。 您可以在重構時混合使用這兩種方法,只需確保一致(例如,僅對應用程序的所有部分中使用的配置數據使用單例方法)。

為了進一步改進使用配置數據的設計,請記住以下(可能)未來的功能要求:更新配置文件時,將重新加載配置數據並在應用程序中使用。 大多數日志記錄框架都設法支持此功能需求,而不會影響多線程應用程序的性能。 除其他外,它需要以下您的應用程序:

  • 如果新的配置數據不好,程序不會終止,但會記錄錯誤,舊的配置數據仍在使用中。 您的初始化過程將需要處理“重新加載時加載”和“重新加載”方案。 要消除這一點的主要原因是您的初始化過程需要可重用,並且不應影響應用程序的其他(運行)部分(再次隔離)。
  • 長期存在的對象可能不會保留配置數據的本地副本或對ConfigForThisModule實例的ConfigForThisModule ,而是應該定期調用Settings.getInstance()... (或其他一些可以返回更新實例的方法)。
  • 用新配置替換舊配置可能不會導致錯誤。 從技術上講,替換配置就像使用Settings.getInstance()...返回的新配置實例更新AtomicReference一樣簡單。 但這也是測試配置數據集的隔離的地方:使用一個模塊中的舊集合和另一個模塊中的新集合應該沒有問題。

配置數據可以看作是一種“全局狀態”。 考慮到這一點,在以下兩個問題中討論了關於做什么和避免什么(部分公然復制到這個答案)的進一步設計要點:

對不起,問題有點模糊,您是否希望存儲配置或程序其他部分使用的緩存對象?

由於您有100個參數,所以首先將配置拆分為可管理的塊

1)將配置參數拆分為與簡單屬性文件1:1對應的邏輯塊 - 需要一些時間

2)這些屬性文件必須外部化,以便您可以在任何時間點更改它們,確保通過env變量將基本位置傳遞給程序

3)編寫一個包含Apache commons配置的實用程序類(singleton)來保存你的配置。 (從基本位置讀取* .properties並將屬性合並到一個配置對象中)這必須在任何線程啟動之前完成。

4)使用config.getXXXX()方法參考代碼中的配置參數

當您的屬性文件在文件系統上發生更改時,Apache commons config還能夠重新加載配置。

完成后,使用像Spring或Guice這樣的DI容器來緩存已配置的對象。

如果它只是你需要的String屬性值,你甚至不需要一個類 - 已經存在一個全局工具: System.getProperties()

您需要做的就是首先在啟動時加載屬性值:

System.setProperty("myKey", "myValue"); // see below how load properties from a file

然后在代碼中的任何位置讀取它:

String myValue = System.getProperty("myKey");

要么

String myValue = System.getProperty("myKey", "my desired default");

如果您的容器不支持開箱即用的屬性加載,則從外部文件加載屬性,如下所示:

key1=value
key2=some other value
etc...

你可以使用這段代碼:

Files.lines(Paths.get("path/to/file"))
  .filter(line -> !line.startsWith("#") || !line.contains("=")) // ignore comment/blank
  .map(line -> line.split("=", 2)) // split into key/value
  .forEach(split -> System.setProperty(split[0], split[1])); // load as property

你可以使用Java Properties類util,基本上它是一個HashTable引用: https//docs.oracle.com/javase/7/docs/api/java/util/Properties.html

您創建文件fileName.properties並將數據存儲在鍵值對中,例如:

username=your name
port=8080

然后將其加載到Properties對象中並獲取如下數據:

Properties prop = new Properties();
load the file...
String userName = prop.getProperty("username")
String port = prop.getProperty("port")// you can parse it to int if needed

我建議為每種類型的配置創建一個屬性文件,如:

  1. clientData.properties
  2. appConfig.properties

你可以按照這個簡單的教程http://www.mkyong.com/java/java-properties-file-examples/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM