Spring Boot配置檔案application.properties說明指南
Spring Boot附帶了一個使用名為application.properties的檔案進行應用程式配置的內建機制。在本文中,我將向您 展示如何在自定義方案中有效使用application.properties檔案 。
我不打算討論Spring Boot框架指定的屬性。使用現有配置鍵非常簡單。您可以 在官方文件中 輕鬆 找到常用配置 key-value。
這篇文章介紹了定義自定義屬性,處理資料型別以及在不同的執行時環境中使用屬性。如果那就是你要找的東西,繼續閱讀。
application.properties基礎知識
application.properties檔案只不過是配置屬性的簡單鍵值儲存。您可以將配置檔案捆綁在應用程式jar中,或將該檔案放在執行時環境的檔案系統中,並在 Spring Boot啟動 時載入它。
簡而言之,您可以使用application.properties檔案:
- 配置Spring Boot框架,
- 定義應用程式自定義配置屬性。
在預設位置建立application.properties
Spring Boot會自動從專案類路徑載入application.properties檔案。您所要做的就是在 src / main / resources 目錄下建立一個新檔案。
application.properties檔案只是一個常規文字檔案。每行包含屬性鍵,等號和屬性值。空行也是允許的。
這是一個示例屬性:
sbpg.init.welcome-message=Hi there!
您可能想知道屬性鍵是否有任何特定語法。答案是:不,沒有。但是,最好保留預定義Spring Boot屬性中提出的命名約定,以提高檔案的可讀性。
在這種情況下,您可以將鍵視為完全限定的Java類名。您可以通過點符號分割幾個部分來構建鍵。鍵 的最後一部分應描述該屬性的用途。 您可以使用其他部件對多個屬性進行邏輯分組。
使用@Value注入屬性
一旦定義了第一個自定義屬性,就可以在Spring bean中使用它了。您可以使用 @Value 註釋簡單地注入屬性值。註釋在bean建構函式中工作,直接在bean欄位上工作。
@Value 註解接受要注入的屬性的鍵:
- 屬性佔位符($ {...})
- 一種表示式 (#{…})。
通常,表示式更強大,除了屬性解除引用之外,您還可以將它們用於許多其他事情。讓我們暫時保持簡單並使用屬性佔位符。以下是通過bean的建構函式注入屬性值的方法:
@Service <b>class</b> InitService { <b>private</b> <b>final</b> String message; InitService(@Value(<font>"${sbpg.init.welcome-message}"</font><font>) String message) { <b>this</b>.message = message; log.info(message); } </font><font><i>// ...</i></font><font> } </font>
出於同樣的原因,您可以直接在欄位上使用註釋。但是,它會使單元測試更加困難並且可能導致一個非常常見的問題。我稍後會描述這個問題,以便你形成自己的觀點。
@Service <b>class</b> InitService { @Value(<font>"${sbpg.init.welcome-message}"</font><font>) <b>private</b> String message; </font><font><i>// ...</i></font><font> } </font>
如果Spring沒有找到你想要注入的鍵,那麼在嘗試建立bean時它會丟擲 IllegalArgumentException 。
預設屬性值
預設情況下,缺少的屬性會導致異常。但是,您可以決定製作一個可選屬性。當application.properties檔案中缺少鍵時,您可以指示Spring為屬性鍵注入預設值。
這該怎麼做?
您需要通過在屬性鍵之後新增冒號(:)後跟預設值來修改表示式。這是一個例子:
@Value(<font>"${sbpg.init.welcome-message:Hello world}"</font><font>) </font>
為什麼我的@Value為null?
這是SpringBoot新人中的常見問題。讓我們討論下面使用場注入機制的bean。
@Service <b>class</b> DontDoItService { @Value(<font>"${sbpg.init.welcome-message:Hello world}"</font><font>) <b>private</b> String message; </font><font><i>// ...</i></font><font> InitService() { log.info(message); </font><font><i>// prints: null</i></font><font> } } </font>
這段程式碼有什麼問題?
程式碼的作者不理解Spring 在 建立bean 之後 將值注入bean的欄位。並且使用建構函式建立bean,對吧?當你這麼想的時候,這很明顯。您不能將值分配給尚不存在的物件的欄位。
換句話說,首先執行建構函式中的程式碼。注射才會是接下來發生,這就是建構函式注入更安全的原因。
application.properties檔案中的註釋
除了屬性和空行之外,application.properties欄位還可以包含註釋。要註釋一行,只需將雜湊字元放在一行的開頭即可。
#The init message logged at the startup sbpg.init.welcome-message=Hi there!
您只能註解說明整行。一行中間的雜湊字元是文字處理的。從技術上講,您可以將雜湊字元用作屬性鍵或值的一部分。
定義自定義屬性
到目前為止,我們只討論了普通的字串屬性。現在我們將研究其他資料型別。我還將向您展示一些可以在表示式中使用的有用技巧。
1.基本屬性型別:字串,整數,布林值
由於application.properties是一個文字檔案,因此所有定義的值都是字串。但是,如果嘗試將值注入非字串變數,Spring框架足夠智慧,可以自動將字串值轉換為其他型別。
這是一個帶數字和布林文字的示例:
sbpg.init.number=42 sbpg.init.display-number=<b>true</b>
要注入這些值,請使用與字串值相同的表示式。Spring檢測變數型別並將屬性轉換為適當的基元。
InitService(@Value(<font>"${sbpg.init.number}"</font><font>) <b>int</b> number, @Value(</font><font>"${sbpg.init.display-number}"</font><font>) <b>boolean</b> displayNumber) { <b>if</b> (displayNumber) { log.info(</font><font>"Magic number: {}"</font><font>, number); } } </font>
您還可以將屬性注入 原始包裝類, 如 Integer , Boolean , BigDecimal ,甚至是自定義 列舉 。您無需額外的工作。
2.多行字串屬性
如果您有很長的屬性值,可以考慮將其分成幾行以提高可讀性。使用反斜槓字元斷開application.properties檔案中的行。
sbpg.init.welcome-message=Hi there! This value is pretty <b>long</b> \ and that is why I decided to \ <b>break</b> it into multiple lines
請注意,注入的值不包含新行字元。
3. 屬性為陣列,列表或集合
應用程式中的某些屬性可能會定義值集合。在這種情況下,為您的所需屬性鍵指定由逗號分隔的值列表。
sbpg.init.numbers=0,1,1,2,3,5,8
Spring再次為您做轉換。只需將屬性注入陣列變數即可。
InitService(@Value(<font>"${sbpg.init.numbers}"</font><font>) <b>int</b>[] numbers) { </font><font><i>// ...</i></font><font> } </font>
列表和集合之類的集合完全相同。如果屬性的值包含重複項,則只會將一個元素新增到集合中。
InitService(@Value(<font>"${sbpg.init.numbers}"</font><font>) List<Integer> numbers) { </font><font><i>// ...</i></font><font> } </font>
4.列表屬性的自定義分隔符
預設情況下,Spring使用逗號分割您的屬性。沒有辦法逃避逗號。如果你想要一個像分號這樣的分隔符,你該怎麼辦?
sbpg.init.numbers=0;1;1;2;3;5;8
幸運的是,您可以使用不同的分隔符自行拆分屬性。你需要的只是一個簡單的表達。
InitService(@Value(<font>"#{'${sbpg.init.numbers}'.split(';')}"</font><font>) List<Integer> numbers) { </font><font><i>// ...</i></font><font> } </font>
這裡發生了什麼?
Spring將屬性注入為常規字串。用單引號標出它。接下來,在表示式( #{...} )內部,對注入的值呼叫String類的 split() 方法。最後,Spring將結果放入列表中。
或者,您可以將屬性作為常規字串注入並自行拆分。您應該決定什麼對您更具可讀性。
5.屬性為hashmap
注入map比陣列和列表更棘手。讓我們從您應該在application.properties檔案中使用的值的格式開始。
sbpg.init.number-map={KEY1:1, KEY2:2, KEY3:3}
,map幾乎看起來像JSON。唯一的區別是不需要引號。如果您願意,可以將鍵和值包裝為引號。Spring會為你開啟它們。
最後一步是使用 @Value 註釋注入屬性。為此,請將屬性佔位符放在表示式中。如果沒有表示式,Spring將丟擲 IllegalStateException 。
InitService(@Value(<font>"#{${sbpg.init.number-map}}"</font><font>) Map<String, Integer> numberMap) { </font><font><i>// ...</i></font><font> } </font>
6. 自定義屬性的命名約定
正如我已經提到的,屬性鍵類似於完全限定的Java類名。它不是強制性的,但連線屬性的邏輯分組提高了可讀性。在專案開始時,它似乎是多餘的。但是,專案增長,屬性數量增加。保持您的財產有條理。
根據我的經驗,為所有自定義應用程式屬性使用某種字首也是一個好主意。將它們與內建的Spring屬性區分開來更容易。特別是Spring Boot新人都很欣賞這種方法。
通常,專案有一些名稱的縮寫。您可以將它用作自定義屬性鍵的第一部分。為了演示這種方法,我將 sbpg 放在 本文的 所有示例中,它代表Spring Boot PlayGround。
環境中的application.properties
為清楚起見,我們不會將應用程式配置保留在單獨的位置。通常,我們在幾個不同的環境中執行應用程式。我們將本地機器用於開發,測試環境,最後用於生產伺服器。通常,我們的應用程式的配置應該在每個環境中有所不同。
您有幾種方法可以解決此問題。讓我們來看看Spring提供的功能。
1. 在application.properties中使用環境變數
您可以做的最簡單的事情是使用作業系統中的舊環境變數。Spring允許您將環境變數直接放在屬性佔位符中的application.properties檔案或 @Value 註釋中。
sbpg.init.java-home=This is Java path: ${JAVA_HOME}
Spring在執行時插入值,並使用作業系統中的實際值替換佔位符。
更重要的是,您可以像其他佔位符一樣設定缺失變數的預設值:
sbpg.init.java-home=This is Java path: ${JAVA_HOME:Undefined JAVA_HOME}
2. 配置檔案特定配置
另一種方法是將所有可能的配置檔案捆綁在jar中,並指示應用程式在啟動時應載入哪一個。實現此方法的最簡單方法是使用 Spring配置檔案 。
這該怎麼做?
首先建立具有與主application.properties檔案位於同一位置的屬性的其他檔案。檔名應遵循模式 application- <profile> .properties ,其中 <profile> 應替換為您選擇的配置檔名稱。
接下來,使用適當的配置屬性填充檔案。您可以將公共部分保留在主application.properties檔案中。Spring Boot不會載入其他檔案,除非您告訴框架讀取它們。
最後一步是在所需環境中啟用所選的配置檔案。您可以通過設定名為 spring.profiles.active的 Spring Boot屬性來完成此 操作 。你有兩個選擇:
- 在application.properties中設定 spring.profiles.active
- 將 spring.profiles.active 設定為啟動引數
哪一個更好?這取決於您如何準備部署包。
選項1.按環境分開jar包
如果您希望為每個環境單獨構建程式包,則可以在構建過程中在application.properties檔案中設定活動概要檔案。
spring.profiles.active=dev
您的構建過程需要為其作為構建的一部分所針對的每個環境替換 spring.profiles.active 屬性的值。Maven還具有配置檔案的概念,通常用於分離不同環境的構建。您可以 指示Maven動態替換application.properties中的值 並設定活動的Spring配置檔案。
選項2.適用於所有環境的單罐包裝
如果您按照他的“持續交付”一書中的Jez Humble建議,您可以將完全相同的程式包部署到所有環境中。在這種情況下, application.properties中spring.profiles.active 屬性的值將僅用作預設配置檔案。
接下來,在執行時環境中啟動應用程式時,應將 spring.profiles.active 屬性作為常規VM選項傳遞。此VM選項將覆蓋application.properties中的值。
java -jar app.jar -Dspring.profiles.active=dev
如果不直接執行jar檔案但將應用程式部署到某個servlet容器,請檢視其手冊以瞭解如何傳遞VM選項。
無論您選擇哪個選項,設定活動配置檔案都會導致Spring Boot使用環境專用屬性載入所需檔案。
3. 外部化application.property檔案 - 超出jar / war邊界
如果您無法將環境屬性放在jar檔案中,該怎麼辦?例如,我們將密碼儲存在屬性中。即使是處理該應用程式的開發人員,生產憑證也可能保密。
不用擔心,Spring Boot為您提供瞭解決方案。
該框架可以直接從執行時環境的檔案系統載入自定義application.property檔案。您需要做的是將 spring.config.additional-location 屬性設定為放置外部application.properties檔案的目錄。
java -jar app.jar -Dspring.config.additional-location="C:/myapp/path/to/config/"
如果您的應用程式包包含application.properties,則Spring Boot將從具有更高優先順序的外部檔案載入屬性。
結論
總而言之,您應該已經知道如何建立自定義屬性並在應用程式中使用原始和更復雜的資料型別。建立專用於單獨執行時環境的application.properties檔案也不應該成為您的問題。您已經知道有一些方法可以解決這個問題。