Spring和Spring Boot的屬性
1.概述
本教程將展示如何在Spring中設置和使用Properties - 通過Java配置和@PropertySource或通過XML和<property-placeholder>,以及屬性如何在Spring Boot中工作。
2.通過Java註解註冊屬性文件
Spring 3.1還引入了新的@PropertySource註解,作為向環境添加屬性源的便捷機制。此註解將與基於Java的配置和@Configuration批註結合使用:(註意,只能引入properties,不能引入yml)
@Configuration @PropertySource("classpath:foo.properties")public class PropertiesWithJavaConfig { //... }
註冊新屬性文件的另一個非常有用的方法是使用占位符來允許您在運行時動態選擇正確的文件 ; 例如:
@PropertySource({ "classpath:persistence-${envTarget:mysql}.properties" })
2.1.定義多個屬性位置(多數據源)
該@PropertySource註釋是可重復的,根據java8的約定。因此,如果我們使用Java 8或更高版本,我們可以使用此批註來定義多個屬性位置:
@PropertySource("classpath:foo.properties") @PropertySource("classpath:bar.properties") public class PropertiesWithJavaConfig { //... }
當然,我們也可以使用@PropertySources註釋並指定一個@PropertySource數組。這適用於任何受支持的Java版本,而不僅僅是Java 8或更高版本:
@PropertySources({ @PropertySource("classpath:foo.properties"), @PropertySource("classpath:bar.properties") }) publicclass PropertiesWithJavaConfig { //... }
在任何一種情況下,值得註意的是,在屬性名稱沖突的情況下,最後一個源數據中的屬性優先。
3.以XML格式註冊屬性文件
在XML中,新的屬性文件可以通過<context:property-placeholder … > 進行訪問到spring的命名空間元素:
<context:property-placeholder location="classpath:foo.properties" />
該foo.properties文件應在放在/src/main/resources,使其可在運行時在類路徑下能找到。
如果Spring上下文中存在多個<property-placeholder>元素,則有一些建議的最佳實踐:
- order屬性需要被指定為固定的
3.1.以XML格式註冊多個屬性文件
在上一節中,我們了解了如何使用Java 8或更高版本中的註釋定義多個屬性文件。同樣,我們可以使用XML配置定義多個屬性文件:
<context:property-placeholder location="classpath:foo.properties, classpath:bar.properties"/>
並且,和以前一樣,如果屬性名稱沖突,則最後一次源讀取優先。
4.使用/註入屬性
使用@Value註解註入屬性非常簡單:
@Value( "${jdbc.url}" ) private String jdbcUrl;
還可以指定屬性的默認值:
@Value( "${jdbc.url:aDefaultUrl}" ) private String jdbcUrl;
在Spring XML配置中使用屬性:
<bean id="dataSource"> <property name="url" value="${jdbc.url}" /> </bean>
舊版PropertyPlaceholderConfigurer和Spring 3.1中添加的新PropertySourcesPlaceholderConfigurer都解析了 bean定義屬性值和@Value註釋中的$ {...}占位符。
最後 - 我們可以 使用Environment API 獲取屬性的值 :
@Autowired private Environment env; ... dataSource.setUrl(env.getProperty("jdbc.url"));
一個非常重要的警告是使用<property-placeholder>不會將屬性公開給Spring環境 - 這意味著檢索這樣的值將不起作用 - 下面將返回null:
env.getProperty("key.something")
5. Spring Boot屬性
在我們進入屬性的更高級配置選項之前,讓我們花一些時間來查看Spring Boot中的新屬性支持。
一般來說,與標準Spring相比,這種新的支持涉及更少的配置,這當然是Boot的主要目標之一。
5.1.application.properties - 默認屬性文件
Boot將其典型約定應用於屬性文件的配置方法。這意味著我們可以簡單地將“ application.properties ”文件放在我們的“ src/main/resources”目錄中,它將被自動檢測到。然後我們可以正常註入任何加載的屬性。
因此,通過使用此默認文件,我們不必顯式註冊PropertySource,甚至不必提供屬性文件的路徑。
如果需要,我們還可以在運行時使用環境屬性配置不同的文件:
java -jar app.jar --spring.config.location=classpath:/another-location.properties
5.2.環境特定屬性文件
如果我們需要針對不同的環境,那麽Boot中就有一個內置機制。
我們可以簡單地在“src/main/resources”目錄中定義“application-environment.properties”文件- 然後使用相同的環境名稱設置Spring配置文件。
例如,如果我們定義一個“staging”環境,那意味著我們必須定義一個staging配置文件,然後定義application-staging.properties。
此env文件將被加載,並將優先於默認屬性文件。請註意,仍將加載默認文件,只是在存在屬性沖突時,環境特定屬性文件優先。
5.3.測試特定屬性文件
當我們的應用程序正在測試時,我們可能還需要使用不同的屬性值。
Spring Boot通過在測試運行期間查看我們的“ src / test / resources ”目錄來為我們處理這個問題。同樣,默認屬性仍然可以正常註入,但如果發生沖突,將覆蓋這些屬性。
5.4.@TestPropertySource註解
如果我們需要對測試屬性進行更精細的控制,那麽我們可以使用@TestPropertySource註釋。
這允許我們為特定測試上下文設置測試屬性,優先於默認屬性源:
@ContextConfiguration @TestPropertySource("/my-test.properties") public class IntegrationTests { // tests }
如果我們不想使用文件,我們可以直接指定名稱和值:
@ContextConfiguration @TestPropertySource("foo=bar", "bar=foo") public class IntegrationTests { // tests }
我們也可以使用@SpringBootTest註釋的屬性參數來實現類似的效果:
@SpringBootTest(properties = {"foo=bar", "bar=foo"}) public class IntegrationTests { // tests }
5.5.分層屬性
如果我們將屬性組合在一起,我們可以使用@ConfigurationProperties批註,它將這些屬性層次結構映射到Java對象中。
我們來看一些用於配置數據庫連接的屬性:
database.url=jdbc:postgresql:/localhost:5432/instance database.username=foo database.password=bar
然後讓我們使用註釋將它們映射到數據庫對象:
@ConfigurationProperties(prefix = "database") public class Database { String url; String username; String password; // standard getters and setters }
Spring Boot再次將其約定應用於配置方法,自動映射屬性名稱及其相應字段。我們需要提供的只是屬性前綴。
5.6.替代方案 - YAML文件
還支持YAML文件。
所有相同的命名規則適用於特定於測試,特定於環境和默認的屬性文件。唯一的區別是文件擴展名,以及對類路徑上的SnakeYAML庫的依賴性。
YAML特別適用於分層財產存儲; 以下屬性文件:
database.url=jdbc:postgresql:/localhost:5432/instance database.username=foo database.password=bar secret: foo
與以下YAML文件同義:(yml以空格作為解析格式,不同級的屬性之間,縮進兩個空格)
database: url: jdbc:postgresql:/localhost:5432/instance username: foo password: bar secret: foo
還值得一提的是,YAML文件不支持@PropertySource註釋,因此如果需要使用註釋,則會限制我們使用屬性文件。
5.7.命令行參數中的屬性
與使用文件相反,屬性可以直接在命令行上傳遞:
java -jar app.jar --property="value"
您也可以通過系統屬性執行此操作,系統屬性在-jar命令之前而不是之後提供:
java -Dproperty.name="value" -jar app.jar
5.8.環境變量的屬性
Spring Boot還會檢測環境變量,將它們視為屬性:
export name=value
java -jar app.jar
5.9.屬性值隨機化
如果我們不想要確定性屬性值,可以使用RandomValuePropertySource隨機化屬性值:
random.number=${random.int} random.long=${random.long} random.uuid=${random.uuid}
5.10.其他類型的屬性來源
Spring Boot支持眾多屬性源,實現了一個經過深思熟慮的排序,以實現合理的覆蓋。值得查閱官方文檔,這超出了本文的範圍。
6.結論
本文展示了在Spring中使用屬性和屬性文件的幾個示例。
Spring和Spring Boot的屬性