SpringBoot入門筆記09——屬性配置檔案詳解以及多環境配置
SpringBoot的外部配置
Spring Boot允許將配置外部化(externalize) ,這樣你就能夠在不同的環境下使用相同的程式碼。你可以使用properties檔案,YAML檔案,環境變數和命令列引數來外部化配置。使用@Value註解,可以直接將屬性值注入到beans中,然後通過Spring的 Environment 抽象或通過 @ConfigurationProperties 繫結到結構化物件來
訪問。
Spring Boot設計了一個非常特別的 PropertySource 順序,以允許對屬性值進行合理的覆蓋,屬性會以如下的順序進行設值:
-
home目錄下的devtools全域性設定屬性( ~/.spring-bootdevtools.properties ,如果devtools啟用) 。
-
測試用例上的@TestPropertySource註解。
-
測試用例上的@SpringBootTest#properties註解。
-
命令列引數
-
來自 SPRING_APPLICATION_JSON 的屬性(環境變數或系統屬性中內嵌的內聯JSON) 。
-
ServletConfig 初始化引數。
-
ServletContext 初始化引數。
-
來自於 java:comp/env 的JNDI屬性。
-
Java系統屬性(System.getProperties()) 。
-
作業系統環境變數。
-
RandomValuePropertySource,只包含 random.* 中的屬性。
-
沒有打進jar包的Profile-specific應用屬性( application-{profile}.properties 和YAML變數) 。
-
打進jar包中的Profile-specific應用屬性( application-{profile}.properties 和YAML變數) 。
-
沒有打進jar包的應用配置( application.properties 和YAML變數) 。
-
打進jar包中的應用配置( application.properties 和YAML變數) 。
-
@Configuration 類上的 @PropertySource 註解。
-
預設屬性(使用 SpringApplication.setDefaultProperties 指定) 。
下面是具體的示例,假設你開發一個使用name屬性的 @Component :
import org.springframework.stereotype.*
import org.springframework.beans.factory.annotation.*
@Component
public class MyBean {
@Value("${name}")
private String name;
// ...
}
你可以將一個 application.properties 放到應用的classpath下,為 name 提供一個合適的預設屬性值。當在新的環境中執行時,可以在jar包外提供一個 application.properties 覆蓋 name 屬性。對於一次性的測試,你可以使用特定的命令列開關啟動應用(比如, java -jar app.jar --name=“Spring” ) 。
注 SPRING_APPLICATION_JSON 屬性可以通過命令列的環境變數設定,例如,在一個UNIX shell中可以這樣:
$ SPRING_APPLICATION_JSON='{"foo":{"bar":"spam"}}' java -jar myapp.jar
本示例中,如果是Spring Environment ,你可以以 foo.bar=spam 結尾;如果在一個系統變數中,可以提供作為 spring.application.json 的JSON字串:
$ java -Dspring.application.json='{"foo":"bar"}' -jar myapp.jar
或命令列引數:
$ java -jar myapp.jar --spring.application.json='{"foo":"bar"}'
或作為一個JNDI變數java:comp/env/spring.application.json
。
自定義屬性與載入
我們在使用Spring Boot的時候,通常也需要定義一些自己使用的屬性,我們可以如下方式直接定義:
com.text.name.name=姓名
com.text.title=Spring Boot標題
然後通過@Value("${屬性名}")
註解來載入對應的配置屬性,具體如下:
@Component
public class BlogProperties {
@Value("${com.text.name}")
private String name;
@Value("${com.text.title}")
private String title;
// 省略getter和setter
}
引數間的引用
在application.properties
中的各個引數之間也可以直接引用來使用,就像下面的設定:
web.upload-path=D:/images
spring.resources.static-locations=classpath:file:${web.upload-path}
spring.resources.static-locations引數引用了上文中定義的web.upload-path屬性
使用隨機數
在一些情況下,有些引數我們需要希望它不是一個固定的值,比如金鑰、服務埠等。Spring Boot的屬性配置檔案中可以通過${random}
來產生int值、long值或者string字串,來支援屬性的隨機值。
//隨機字串
my.secret=${random.value}
//隨機int
my.number=${random.int}
//隨機long
my.bignumber=${random.long}
//10以內的隨機數
my.number.less.than.ten=${random.int(10)}
//1024--65535
my.number.in.range=${random.int[1024,65536]}
random.int* 語法是 OPEN value (,max) CLOSE ,此處 OPEN,CLOSE 可以是任何字元,並且 value,max 是整數。如果提供 max ,那麼 value 是最小值, max 是最大值(不包含在內) 。
通過命令列設定屬性值
預設情況下, SpringApplication 會將所有命令列配置引數(以’–'開頭,比如 --server.port=9000 ) 轉化成一個 property ,並將其新增到SpringEnvironment 中。連續的兩個減號--
就是對application.properties
中的屬性值進行賦值的標識。正如以上章節提過的,命令列屬性總是優先於其他屬性源。
通過命令列來修改屬性值固然提供了不錯的便利性,但是通過命令列就能更改應用執行的引數,那豈不是很不安全?是的,所以Spring Boot也貼心的提供了遮蔽命令列訪問屬性的設定,只需要這句設定就能遮蔽:SpringApplication.setAddCommandLineProperties(false)
。
多環境配置
SpringApplication 將從以下位置載入 application.properties 檔案,並把
它們新增到Spring Environment 中:
- 當前目錄下的 /config 子目錄。
- 當前目錄。
- classpath下的 /config 包。
- classpath根路徑(root) 。
該列表是按優先順序排序的(列表中位置高的路徑下定義的屬性將覆蓋位置低的) 。
我們在開發Spring Boot應用時,通常同一套程式會被應用和安裝到幾個不同的環境,比如:開發、測試、生產等。其中每個環境的資料庫地址、伺服器埠等等配置都會不同,如果在為不同環境打包時都要頻繁修改配置檔案的話,那必將是個非常繁瑣且容易發生錯誤的事。
對於多環境的配置,各種專案構建工具或是框架的基本思路是一致的,通過配置多份不同環境的配置檔案,再通過打包命令指定需要打包的內容之後進行區分打包,Spring Boot也不例外,或者說更加簡單。
在Spring Boot中多環境配置檔名需要滿足application-{profile}.properties
的格式,其中{profile}
對應你的環境標識,比如:
application-dev.properties
:開發環境application-test.properties
:測試環境application-prod.properties
:生產環境
至於哪個具體的配置檔案會被載入,需要在application.properties
檔案中通過spring.profiles.active
屬性來設定,其值對應{profile}
值。
如:spring.profiles.active=test
就會載入application-test.properties
配置檔案內容
下面,以不同環境配置不同的服務埠為例,進行樣例實驗。
- 針對各環境新建不同的配置檔案
application-dev.properties
、application-test.properties
、application-prod.properties
- 在這三個檔案均都設定不同的
server.port
屬性,如:dev環境設定為1111,test環境設定為2222,prod環境設定為3333 - application.properties中設定
spring.profiles.active=dev
,就是說預設以dev環境設定 - 測試不同配置的載入
- 執行
java -jar xxx.jar
,可以觀察到服務埠被設定為1111
,也就是預設的開發環境(dev) - 執行
java -jar xxx.jar --spring.profiles.active=test
,可以觀察到服務埠被設定為2222
,也就是測試環境的配置(test) - 執行
java -jar xxx.jar --spring.profiles.active=prod
,可以觀察到服務埠被設定為3333
,也就是生產環境的配置(prod)
- 執行
按照上面的實驗,可以如下總結多環境的配置思路:
application.properties
中配置通用內容,並設定spring.profiles.active=dev
,以開發環境為預設配置application-{profile}.properties
中配置各個環境不同的內容- 通過命令列方式去啟用不同環境的配置