Spring Boot提供了兩種經常使用的配置文件,分別是properties文件和yml文件。html
他們的做用都是修改Spring Boot自動配置的默認值。相對於properties文件而言,yml文件更年輕,也有不少的坑。可謂成也蕭何敗也蕭何,yml經過空格來肯定層級關係,使配置文件結構更清晰,但也會由於微不足道的空格而破壞了層級關係。java
yml是YAML(YAML Ain't Markup Language)語言的文件,以數據爲中心,比json、xml等更適合作配置文件程序員
之前的配置文件;大多都使用的是 xxxx.xml文件;yml和xml相比,少了一些結構化的代碼,使數據更直接,一目瞭然。舉例:spring
YAMLsql
server: port: 8081
XML:json
<server> <port>8081</port> </server>
yml和json呢?沒有誰好誰壞,合適纔是最好的。yml的語法比json優雅,註釋更標準,適合作配置文件。json做爲一種機器交換格式比yml強,更適合作api調用的數據交換。api
k:(空格)v:表示一對鍵值對(空格必須有);數組
以空格的縮進程度來控制層級關係。空格的個數並不重要,只要左邊空格對齊則視爲同一個層級。注意不能用tab代替空格。且大小寫敏感。springboot
server: port: 8081 path: /hello
YAML支持字面值,對象,數組三種數據結構,也支持複合結構。數據結構
【字面值】——字符串,布爾類型,數值,日期。
k: v:字面直接來寫;
字符串默認不用加上單引號或者雙引號;
"":雙引號;不會轉義字符串裏面的特殊字符;特殊字符會做爲自己想表示的意思
name: "zhangsan \n lisi":輸出;zhangsan 換行 lisi
'':單引號;會轉義特殊字符,特殊字符最終只是一個普通的字符串數據
name: ‘zhangsan \n lisi’:輸出;zhangsan \n lisi
【對象】
由鍵值對組成,形如 key:(空格)value 的數據組成。冒號後面的空格是必需要有的,每組鍵值對佔用一行,且縮進的程度要一致。
friends: lastName: zhangsan age: 20
也可使用行內寫法:{k1: v1, ....kn: vn}
friends: {lastName: zhangsan,age: 18}
【數組】——List、Set
由形如 -(空格)value 的數據組成。短橫線後面的空格是必需要有的,每組數據佔用一行,且縮進的程度要一致,也可使用行內寫法: [1,2,...n]
pets: - cat - dog - pig
行內寫法
pets: [cat,dog,pig]
建立一個Spring Boot 的全局配置文件 application.yml,配置屬性參數。
person: lastName: hello age: 18 boss: false birth: 2019/7/14 maps: {k1: v1,k2: v2} lists: - zhangsan - lisi dog: name: 小狗 age: 12
建立實體類Person.java 獲取配置文件中的屬性值,經過註解@ConfigurationProperties獲取配置文件中的指定值並注入到實體類中。
/** * 將配置文件中配置的每個屬性的值,映射到這個組件中 * @ConfigurationProperties:告訴SpringBoot將本類中的全部屬性和配置文件中相關的配置進行綁定; * prefix = "person":配置文件中哪一個下面的全部屬性進行一一映射 * * 只有這個組件是容器中的組件,才能容器提供的@ConfigurationProperties功能; * */ @Component @ConfigurationProperties(prefix = "person") public class Person { private String lastName; private Integer age; private Boolean boss; private Date birth; private Map<String,Object> maps; private List<Object> lists; private Dog dog; // 省略getter,setter,toString方法 }
咱們能夠導入配置文件處理器,之後編寫配置就有提示了
<!--導入配置文件處理器,配置文件進行綁定就會有提示--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
建立一個單元測試類:
/** * SpringBoot單元測試; * * 能夠在測試期間很方便的相似編碼同樣進行自動注入等容器的功能 * */ @RunWith(SpringRunner.class) @SpringBootTest public class PersonTest { @Autowired private Person person; @Test public void test() { System.out.println(person); } }
注意:在運行測試類以前,要確保spring boot的引導類(主程序)是已啓動狀態。
properties文件常常用,這裏就簡單介紹一下。其語法結構形如:key=value。
userinfo.account=zhangsan userinfo.age=25 userinfo.active=true userinfo.created-date=2019/07/14 16:54:30 userinfo.map.k1=v1 userinfo.map.k2=v2 userinfo.list=one,two,three
從配置文件中取值注入到實體類中,和YAML是同樣的。
/** * 用戶信息 * @ConfigurationProperties : 被修飾類中的全部屬性會和配置文件中的指定值(該值經過prefix找到)進行綁定 */ @Component @ConfigurationProperties(prefix = "userinfo") public class UserInfo { private String account; private Integer age; private Boolean active; private Date createdDate; private Map<String, Object> map; private List<Object> list; // 省略getter,setter,toString方法 }
注意:properties配置文件在idea中默認utf-8可能會亂碼。調整以下:
【注意】:spring boot項目中同時存在application.properties和application.yml文件時,兩個文件都有效,可是application.properties的優先級會比application.yml高。
Spring Boot經過ConfigurationProperties註解從配置文件中獲取屬性。從上面的例子能夠看出ConfigurationProperties註解能夠經過設置prefix指定須要批量導入的數據。支持獲取字面值,集合,Map,對象等複雜數據。ConfigurationProperties註解還有其餘特麼呢?它和Spring的Value註解又有什麼區別呢?帶着這些問題,咱們繼續往下看。
ConfigurationProperties註解的優缺點
Value註解的優缺點正好相反,它只能一個個配置注入值;不支持數組、集合等複雜的數據類型;不支持數據校驗;對屬性名匹配有嚴格的要求。最大的特色是支持SpEL表達式,使其擁有更豐富的功能。
第一步:導入依賴。若要使用ConfigurationProperties註解,須要導入依賴 spring-boot-configuration-processor;
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
第二步:配置數據。在application.yml配置文件中,配置屬性參數,其前綴爲employee,參數有字面值和數組,用來判斷是否支持獲取複雜屬性的能力;(nick-name是用來判斷匹配屬性的鬆散性,若換成nick_name依然能夠獲取值。)
employee: nick-name: itachi email: 123456@126.com phone: 1234567 abilities: [java,sql,html] created_date: 2019/7/14 13:40
第三步:匹配數據。在類上添加註解ConfigurationProperties,並設置prefix屬性值爲employee。並把該類添加到Spring的IOC容器中。
第四步:校驗數據。添加數據校驗Validated註解,開啓數據校驗,測試其是否支持數據校驗的功能;
第五步:測試ConfigurationProperties註解是否支持SpEL表達式;
/** * ConfigurationProperties 註解語法類 * 第一步:導入依賴 spring-boot-configuration-processor; * 第二步:把ConfigurationProperties註解修飾的類添加到Spring的IOC容器中; * 第三步:設置prefix屬性,指定須要注入屬性的前綴; * 第四步:添加數據校驗註解,開啓數據校驗; * * 注意點: * 1、nickName和createdDate在yml配置文件中,對應參數分別是中劃線和下劃線,用於測試其對屬性名匹配的鬆散性 * 2、email和iphone 測試其支持JSR303數據校驗 * 3、abilities 測試其支持複雜的數據結構 */ @Component @ConfigurationProperties(prefix = "employee") @Validated public class ConfigurationPropertiesEntity { private String nickName; // 解析成功,支持鬆散匹配屬性 private String email; // @Email //表示phone必須填成email格式。此處解析失敗:Binding validation errors on employee private String phone; private List<String> abilities; private Date createdDate; // 解析成功,支持鬆散匹配屬性 // @ConfigurationProperties("#{11*2}") //語法報錯,不支持SpEL表達式:not applicable to field private String operator; // 省略get/set和toString方法 }
第一步:在屬性上添加Value註解,經過${}設置參數從配置文件中注入值;
第二步:修改${employee.ceatred_date}
中的參數值,改成${employee.ceatredDate}
測試是否能解析成功;
第三步:添加數據校驗Validated註解,開啓數據校驗,測試其是否支持數據校驗的功能;
第四步:測試Value註解是否支持SpEL表達式;
/** * Value 註解語法類 * 第一步:在屬性上添加註解Value注入參數 * 第二步:把Value註解修飾的類添加到Spring的IOC容器中; * 第三步:添加數據校驗註解,檢查是否支持數據校驗; * * 注意點: * 1、nickName和createdDate在yml配置文件中,對應參數分別是中劃線和下劃線,用於測試其對屬性名匹配的鬆散性 * 2、email和iphone 測試其支持JSR303數據校驗 * 3、abilities 測試其支持複雜的數據結構 * * 結論: * 1、createDate取值必須和yml配置文件中的參數保持一致, * 2、既是在iphone上添加郵箱驗證註解依然能夠經過測試, * 3、不支持複雜的數據結構,提示錯誤和第一條相同:IllegalArgumentException: Could not resolve placeholder 'itdragon.abilities' in value "${itdragon.abilities}" */ @Component @Validated public class ValueEntity { @Value("${employee.nick-name}") private String nickName; @Value("${employee.email}") private String email; @Email @Value("${employee.phone}") // 解析成功,並不支持數據校驗 private String phone; // @Value("${employee.abilities}") //解析錯誤,並不支持複雜的數據結構 private List<String> abilities; // @Value("${employee.createDate}") // 解析錯誤,並不支持鬆散匹配屬性,必須嚴格一致 @Value("${employee.created_date}") private Date createDate; // Value註解的強大一面:支持SpEL表達式 @Value("#{11*2}") // 算術運算 private String operator; @Value("#{1>2 || 2<=3}") // 關係運算 private Boolean comparison; @Value("#{systemProperties['java.version']}") //系統配置:os.name private String systemProperties; @Value("#{T(java.lang.Math).abs(-18)}") // 表達式 private String mapExpression; // 省略get/set和toString() }
若是說,咱們只是在某個業務邏輯中須要獲取一下配置文件中的某項值,使用@Value;
若是說,咱們專門編寫了一個javaBean來和配置文件進行映射,咱們就直接使用@ConfigurationProperties;
@ConfigurationProperties註解默認只能讀取系統全局的配置文件,要加載非全局的配置,須要使用@PropertySource加載文件。@PropertySource的目的是加載指定的屬性文件。
好比定義一個person.properties
person.last-name=李四 person.age=12 person.birth=2019/7/14 person.boss=false person.maps.k1=v1 person.maps.k2=14 person.lists=a,b,c person.dog.name=dog person.dog.age=15
若是要在配置類中加載person.properties配置文件,則須要用到@PropertySource
/** * 將配置文件中配置的每個屬性的值,映射到這個組件中 * @ConfigurationProperties:告訴SpringBoot將本類中的全部屬性和配置文件中相關的配置進行綁定; * prefix = "person":配置文件中哪一個下面的全部屬性進行一一映射 * * 只有這個組件是容器中的組件,才能容器提供的@ConfigurationProperties功能; * @ConfigurationProperties(prefix = "person")默認從全局配置文件中獲取值; * */ @PropertySource(value = {"classpath:person.properties"}) @Component @ConfigurationProperties(prefix = "person") public class Person { private String lastName; private Integer age; private Boolean boss; private Date birth; private Map<String, Object> maps; private List<Object> lists; private Dog dog; // 省略get/set和toString()方法 }
編寫一個HelloService.java
public class HelloService { }
編寫一個beans.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="helloService" class="com.pinyougou.service.HelloService"></bean> </beans>
在測試類中測試該配置文件有沒有生效:
@RunWith(SpringRunner.class) @SpringBootTest public class SpringBootConfigApplicationTest { @Autowired private ApplicationContext context; @Test public void testHelloService() { boolean b = context.containsBean("helloService"); System.out.println(b); // false } }
測試代表,Spring Boot裏面沒有Spring的配置文件,咱們本身編寫的配置文件,也不能自動識別;
想讓Spring的配置文件生效,加載進來;可使用@ImportResource標註在一個配置類上:
@ImportResource(locations = {"classpath:beans.xml"}) @SpringBootApplication public class SpringbootdemoApplication { public static void main(String[] args) { SpringApplication.run(SpringbootdemoApplication.class, args); } }
這時候再次運行testHelloService()測試方法,結果爲true。說明本身編寫的beans.xml配置文件已經生效了。
總結:@ImportResource的做用是:導入Spring的配置文件,讓配置文件裏面的內容生效;
雖然使用@ImportResource能導入咱們編寫的配置文件,可是SpringBoot並不推薦這種方式,SpringBoot推薦使用全註解的方式來給容器中添加組件。這時候就使用到了@Bean來給容器中添加組件。
爲了測試效果明顯,將beans.xml刪掉,而且將@ImportResource註釋掉:
建立一個配置類:
/** * @Configuration:指明當前類是一個配置類;就是來替代以前的Spring配置文件。@Configuration可理解爲用spring的時候xml裏面的<beans>標籤。 * @Configuration標註在類上,至關於把該類做爲spring的xml配置文件中的<beans>,做用爲:配置spring容器(應用上下文對象) */ @Configuration public class MyAppConfig { // 將方法的返回值添加到容器中;容器中這個組件默認的id就是方法名 // @Bean標註在方法上(返回某個實例的方法),等價於spring配置文件中的<bean></bean>,做用爲:註冊bean對象 // @Bean可理解爲用spring的時候xml裏面的<bean>標籤。 @Bean public HelloService helloService() { System.out.println("配置了@Bean給容器中添加了組件。。。"); return new HelloService(); } }
再次運行測試類:
注意:
Spring Boot不是spring的增強版,因此@Configuration和@Bean一樣能夠用在普通的spring項目中。
佔位符和隨機數比較簡單,這裏就直接貼出代碼。須要注意的是:
ran: # 這裏的prefix不能是random, ran-value: ${random.value} ran-int: ${random.int} ran-long: ${random.long} ran-int-num: ${random.int(10)} ran-int-range: ${random.int[10,20]} ran-placeholder: placeholder_${ran.ran-value:此處不能有空格,且key爲完整路徑} /** * 隨機數和佔位符語法類 */ @Component @ConfigurationProperties(prefix = "ran") public class RandomEntity { private String ranValue; // 隨機生成一個字符串 private Integer ranInt; // 隨機生成一個整數 private Long ranLong; // 隨機生成一個長整數 private Integer ranIntNum; // 在指定範圍內隨機生成一個整數 private Integer ranIntRange;// 在指定區間內隨機生成一個整數 private String ranPlaceholder;// 佔位符 // 省略getter,setter,toString方法e }
測試代碼:
@RunWith(SpringRunner.class) @SpringBootTest public class SpringBootYmlApplicationTests { @Autowired private RandomEntity randomEntity; @Test public void contextLoads() { System.out.println("Random Grammar : " + randomEntity); } }
咱們在主配置文件編寫的時候,文件名能夠是 application-{profile}.properties。如:
application-dev.properties
application-prod.properties
application.properties主配置文件
運行主程序時,默認使用的是application.properties主配置文件的端口號:8080
當咱們要激活指定的profile時,好比要激活開發環境的8081端口,能夠在主配置文件中添加spring.profiles.active=dev
yml支持多文檔塊方式
server: port: 8080 spring: profiles: active: prod #指定使用生產環境運行 --- server: port: 8081 spring: profiles: dev --- server: port: 8082 spring: profiles: prod
除了在配置文件中經過代碼來激活指定的profile,還能夠經過命令行和指定虛擬機參數的方式來激活指定的profile。
【命令行】
能夠直接在測試的時候,配置傳入命令行參數:
此外,若是將項目package後,也能夠經過命令行的方式來指定profile:
【虛擬機參數】
springboot 啓動會掃描如下位置的application.properties或者application.yml文件做爲Spring boot的默認配置文件
file:./config/
file:./
classpath:/config/
classpath:/
若是存在多個配置文件,則嚴格按照優先級進行覆蓋,最高者勝出。以下圖1~4優先級從高到低:
SpringBoot會從這四個位置所有加載主配置文件;互補配置;
咱們還能夠經過spring.config.location來改變默認的配置文件位置。
項目打包好之後,咱們可使用命令行參數的形式,啓動項目的時候來指定配置文件的新位置;指定配置文件和默認加載的這些配置文件共同起做用造成互補配置;
java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --spring.config.location=G:/application.properties