? ? ? 配置文件解析(下)
?????????????????????????????????????????????????????????????????????????????????????????????????原創(chuàng)者:文思
一、yml(YAML Ain’t Markup Language)基本用法
application.properties或application.yml
配置文件的作用:修改springboot的默認(rèn)配置系馆。
YAML:以數(shù)據(jù)為中心,比json遇汞,xml等更適合做配置文件
基本語法:
K:(空格)V :表示一對鍵值對宪哩。以空格的縮進(jìn)來控制層級關(guān)系褂策,只要是左對齊的一列數(shù)據(jù),都是一個層級的峭判。
值的寫法:
字面量:普通的值(數(shù)據(jù)、字符串棍好、布爾)仗岸,k: v形式直接來寫。如果有特殊字符借笙,不需要轉(zhuǎn)義可用雙引號爹梁,需要轉(zhuǎn)義可用單引號。
對象提澎、Map:k: v形式直接來寫姚垃,在下一行寫對象的屬性和值,注意縮進(jìn)盼忌。
還可以使用行內(nèi)寫法:friends:{name:zhangsan,age: 18}
數(shù)組(List积糯、Set):用- 值表示數(shù)組中的一個元素
示例:
新建一個yml配置文件:
server:
?????port: 8081
person:
?????lastName: zhangsan
?????age: 18
?????boss:??false
?????birth:? 2018/7/17
?map:? {t1:test1,t2:test2,t3:test3}
?map2:
???t1:? test11
???t2:? test22
???t3:? test33
list:
???-? lisi
???-? wangwu
???-? zhaoliu
?dog:
? ? name:? 小狗
????age:? 2
創(chuàng)建對應(yīng)的對象:
@Component//聲明為spring組件,讓spring容器管理
@ConfigurationProperties(prefix="person")//默認(rèn)從全局配置文件中獲取值,告訴springboot將此類的屬性與配置文件的配置綁定
public classPerson {
??? private String lastName;
??? private Integer age;
??? private Boolean boss;
??? private Date birth;
??? privateMap map;
??? privateMap map2;
??? private List list;
??? private Dog dog;
??? public String toString(){
?????? return "Person{"+
????????????? "lastName="+ lastName+
????????????? ",age="+ age+
????????????? ",boss="+ boss+
????????????? ",birth="+ birth+
????????????? ",map="+ map+
????????????? ",map2="+ map2+
????????????? ",list="+ list+
????????????? ",dog="+ dog+
????????????? "}";
??? }
?.....setter\getter方法略
}
package com.wensi.springbootdemo1.yml;
public classDog {
??? private String name;
??? private Integer age;
??? public String getName() {
?????? return name;
??? }
?.....setter\getter方法略
}
運行測試類:
package com.wensi.springbootdemo1;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.wensi.springbootdemo1.yml.Person;
@RunWith(SpringRunner.class)
@SpringBootTest
public classAppTest{
??? @Autowired
??? Personperson;
??? @Test
??? public void contextLoads(){
?????? System.out.println(person);
??? }
}
運行結(jié)果:
Person{lastName=zhangsan,age=18,boss=false,birth=Tue Jul 17 00:00:00 CST 2018,map={t1=test1, t2=test2, t3=test3},map2={t1=test11,t2=test22, t3=test33},list=[lisi, wangwu,zhaoliu],dog=com.wensi.springbootdemo1.yml.Dog@796d3c9f}
使用properties格式的配置文件application.properties:
person.lastName=zhangsan
person.age=18
person.boss=false
person.birth=2018/7/17
person.map.t1=test1
person.map.t2=test2
person.map.t3=test3
person.list=lisi,wangwu,zhaoliu
person.dog.name=小狗
person.dog.age=2
運行測試類的結(jié)果:
Person{lastName=zhangsan,age=18,boss=false,birth=TueJul 17 00:00:00 CST 2018,map={t3=test3, t2=test2,t1=test1},map2=null,list=[lisi, wangwu,zhaoliu],dog=com.wensi.springbootdemo1.yml.Dog@6f8d7714}
使用@value:
@Component
public class PersonValue {
??? @Value("${person.lastName}")
??? private String lastName;
??? @Value("#{2*11}")
??? private Integer age;
??? @Value("true")
??? privateBooleanboss;
運行結(jié)果:
Person{lastName=zhangsan,age=22,boss=true,birth=null,map=null,map2=null,list=null,dog=null}
@value和@ConfigurationProperties區(qū)別:
例如:
@Component
@ConfigurationProperties(prefix="person")
@Validated
public class Person {
??? private String lastName;//lastName必須是郵箱格式
??? private Integer age;
??? private Boolean boss;
??? private Date birth;
運行結(jié)果:
Binding to targetPerson{lastName=zhangsan,age=18,boss=false,birth=Tue Jul 17 00:00:00 CST2018,map={t3=test3, t2=test2, t1=test1},map2=null,list=[lisi, wangwu,zhaoliu],dog=com.wensi.springbootdemo1.yml.Dog@7689ddef} failed:
??? Property:person.lastName
??? Value:zhangsan
? ? Reason: 不是一個合法的電子郵件地址
使用@value時:
@Component
@Validated
public class PersonValue {
??? @Value("${person.lastName}")
??? private String lastName;
運行結(jié)果:
Person{lastName=zhangsan,age=22,boss=true,birth=null,map=null,map2=null,list=null,dog=null}。說明@value不支持?jǐn)?shù)據(jù)校驗
對于復(fù)雜數(shù)據(jù)類型:
@Component
public class PersonValue {
??? @Value("${person.lastName}")
??? private String lastName;
??? @Value("#{2*11}")
??? private Integer age;
??? @Value("true")
??? private Boolean boss;
??? private Date birth;
??? @Value("${person.map}")
??? private Map map;
運行結(jié)果:
Caused by: java.lang.IllegalArgumentException:Could not resolve placeholder 'person.map' in value "${person.map}"
說明@value不支持復(fù)雜數(shù)據(jù)類型谦纱,如map看成。
使用建議:
如果說,我們只是在某個業(yè)務(wù)邏輯中需要獲取一下配置文件中的某項值跨嘉,使用@Value川慌。
如果說,我們專門編寫了一個javaBean來和配置文件進(jìn)行映射祠乃,我們就直接使用@ConfigurationProperties
@PropertySource和@importResource
根據(jù)名稱分析@PropertySource可加載非默認(rèn)的配置文件梦重,即加載指定的配置文件,當(dāng)我們想將一些特定業(yè)務(wù)所需要的配置與系統(tǒng)默認(rèn)配置分開維護(hù)時亮瓷,需要@PropertySource
@Component
@ConfigurationProperties(prefix="person")
@PropertySource(value={"classpath:person.properties"})
public class PersonPropertySource {
??? private String lastName;
??? privateInteger age;
運行結(jié)果:
Person{lastName=zhangsan,age=18,boss=false,birth=Tue Jul 17 00:00:00 CST 2018,map={t3=test3, t2=test2,
t1=test1},map2=null,list=[lisi, wangwu,zhaoliu],dog=com.wensi.springbootdemo1.yml.Dog@1b32cd16}
@importResource導(dǎo)入spring的配置文件琴拧,讓配置文件里面的內(nèi)容生效
因為springboot里面沒有spring的配置文件,自己編寫地配置文件也不能識別嘱支,所以需要使用@importResource加載進(jìn)來蚓胸。示例:
public class TestImportService {
}
bean.xml:
@SpringBootApplication
@ImportResource(locations = {"classpath:bean.xml"})
public class App
{
……
}
測試用例:
@Autowired
??? ApplicationContext ioc;
??? @Test
??? public void testImportSource(){
?????? System.out.println(ioc.containsBean("testImportService"));
??? }
運行結(jié)果:true
SpringBoot推薦給容器中添加組件的方式:推薦使用全注解的方式
1、配置類@Configuration------>Spring配置文件
2除师、使用@Bean給容器中添加組件,配置類這里使用@Bean注解
/**
* @Configuration:指明當(dāng)前類是一個配置類沛膳;就是來替代之前的Spring配置文件
** 在配置文件中用標(biāo)簽添加組件
*/
@Configuration
public class MyAppConfig {
//將方法的返回值添加到容器中;容器中這個組件默認(rèn)的id就是方法名
????????@Bean
????????public HelloService helloService02(){
????????????System.out.println("配置類@Bean給容器中添加組件了...");
????????????return new HelloService();
????????}
}
配置文件占位符
1汛聚、隨機(jī)數(shù):
${random.value}锹安、${random.int}、${random.long}
${random.int(10)}、${random.int[1024,65536]}
2八毯、占位符獲取之前配置的值搓侄,如果沒有可以是用:指定默認(rèn)值
person.last‐name=張三${random.uuid}
person.age=${random.int}
person.birth=2017/12/15
person.boss=false
person.maps.k1=v1
person.maps.k2=14
person.lists=a,b,c
person.dog.age=15
person.dog.name=${person.hello:hello}_dog?
如果${person.hello: hello}取不到值就默認(rèn)值hello
多profile文件
應(yīng)該對開發(fā)\測試\生產(chǎn)環(huán)境下切換
文件名可以是application-{profile}.properties/yml
默認(rèn)使用的是application.properties/yml
激活指定profile
在配置文件中指定spring.profile.activie=dev,示例瞄桨,新建application-dev.properties:
application.properties中增加spring.profile.activie=dev
Yml格式的多profile:yml支持文檔塊模式
spring:
? profiles:
??? active: prod
---
server:
? port: 8083
spring:
? profiles: prod
---
server:
? port: 8084
spring:
? profiles:dev
運行如圖:
spring.profiles.active是激活使用指定的配置文件话速。
另一種可以使用命令行的方式:java -jar ***.jar –spring.profiles.active=dev
還有一種虛擬機(jī)參數(shù):-Dspring.profiles.active=dev
配置文件加載位置
Spring
boot啟動會掃描以下位置的application.properties或yml作為spring
boot的默認(rèn)配置文件
-file:./config/
-file:./
-classpath:/config/
-classpath:/
以上是按照優(yōu)先級從高到低的順序,所有位置的文件都會被加載芯侥,高優(yōu)先級配置內(nèi)容會覆蓋低優(yōu)先級配置內(nèi)容泊交。
外部配置加載順序
SpringBoot也可以從外部以下位置加載配置; 優(yōu)先級從高到低柱查;高優(yōu)先級的配置覆蓋低優(yōu)先級的配置廓俭,所有的配置會形成互補(bǔ)配置
1.命令行參數(shù)
所有的配置都可以在命令行上進(jìn)行指定
java -jarspring-boot-02-config-02-0.0.1-SNAPSHOT.jar --server.port=8087--server.context-path=/abc
多個配置用空格分開;--配置項=值
2.來自java:comp/env的JNDI屬性
3.Java系統(tǒng)屬性(System.getProperties())
4.操作系統(tǒng)環(huán)境變量
5.RandomValuePropertySource配置的random.*屬性值由jar包外向jar包內(nèi)進(jìn)行尋找唉工;優(yōu)先加載帶profile
6.jar包外部的application-{profile}.properties或application.yml(帶spring.profile)配置文件
7.jar包內(nèi)部的application-{profile}.properties或application.yml(spring.profile)配置文件再來加載不帶profile
8.jar包外部的application.properties或application.yml(不spring.profile)配置文件
9.jar包內(nèi)部的application.properties或application.yml(不spring.profile)配置文件
10.@Configuration注解類上的@PropertySource
11.通過SpringApplication.setDefaultProperties指定的默認(rèn)屬性
示例:
java
-jar springbootdemo1-0.0.1-SNAPSHOT.jar -server.port=8088研乒,
啟動端口就覆蓋配置文件的里的端口設(shè)置了,啟動端口為8088
二淋硝、自動配置原理
配置文件能配置的屬性參照:
觀察@ SpringBootApplication源碼
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
? ? ? ?@Filter(type = FilterType.CUSTOM, classes =
TypeExcludeFilter.class),
?????? @Filter(type = FilterType.CUSTOM, classes =
AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication
1)SpringBoot啟動時候加載主配置類雹熬,開啟了自動配置功能@EnableAutoConfiguration
2) @EnableAutoConfiguration利用EnableAutoConfigurationImportSelector選擇器給容器導(dǎo)入META-INF/Spring.factories中的默認(rèn)配置對應(yīng)的組件。(可查看selectImports()方法-->
List configurations = getCandidateConfigurations(annotationMetadata, attributes);獲取候選的配置-->
SpringFactoriesLoader.loadFactoryNames()//掃描所有jar包類路徑下META‐INF/spring.factories把掃描到的這些文件的內(nèi)容包裝成properties對象從properties中獲取到EnableAutoConfiguration.class類(類名)對應(yīng)的值谣膳,然后把他們添加在容器中)
3)如上每一個自動配置類進(jìn)行自動配置
4) 以HttpEncodingAutoConfiguration(Http編碼自動配置)為例解釋自動配置原理竿报;
@Configuration //表示這是一個配置類,以前編寫的配置文件一樣继谚,也可以給容器中添加組件
@EnableConfigurationProperties(HttpEncodingProperties.class)
//啟動指定類的
ConfigurationProperties功能烈菌;將配置文件中對應(yīng)的值和HttpEncodingProperties綁定起來;并把
HttpEncodingProperties加入到ioc容器中
@ConditionalOnWebApplication
//Spring底層@Conditional注解(Spring注解版)花履,根據(jù)不同的條件芽世,如果
滿足指定的條件,整個配置類里面的配置就會生效诡壁; 判斷當(dāng)前應(yīng)用是否是web應(yīng)用捂襟,如果是,當(dāng)前配置類生效
@ConditionalOnClass(CharacterEncodingFilter.class)
//判斷當(dāng)前項目有沒有這個類
CharacterEncodingFilter欢峰;SpringMVC中進(jìn)行亂碼解決的過濾器葬荷;
@ConditionalOnProperty(prefix= "spring.http.encoding", value = "enabled", matchIfMissing=
true) //判斷配置文件中是否存在某個配置spring.http.encoding.enabled;如果不存在纽帖,判斷也是成立的
//即使我們配置文件中不配置pring.http.encoding.enabled=true宠漩,也是默認(rèn)生效的;
public class HttpEncodingAutoConfiguration{
//他已經(jīng)和SpringBoot的配置文件映射了
private final HttpEncodingPropertiesproperties;
//只有一個有參構(gòu)造器的情況下懊直,參數(shù)的值就會從容器中拿
publicHttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
this.properties =properties;
}
@Bean //給容器中添加一個組件扒吁,這個組件的某些值需要從properties中獲取
@ConditionalOnMissingBean(CharacterEncodingFilter.class)
//判斷容器沒有這個組件?
publicCharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = newOrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
return filter;
}
根據(jù)當(dāng)前不同的條件判斷室囊,決定這個配置類是否生效雕崩?
一但這個配置類生效魁索;這個配置類就會給容器中添加各種組件;這些組件的屬性是從對應(yīng)的properties類中獲取的盼铁,這些類里面的每一個屬性又是和配置文件綁定的
這里能看出配置文件能配置的屬性都是來源于HttpEncodingProperties類粗蔚。
精髓:
1:spring boot啟動會加載大量的自動配置類
2:我們看我們需要的功能有沒有springboot默寫好的自動配置類
3:我們看這個自動配置類中配置了哪些組件(我們要用的有就不用再配置了)
4:給容器中自動配置類添加組件時,會從properties類中獲取某些屬性饶火,我們可以在配置文件中指定這些屬性的值
xxxAutoConfigurartion自動配置類鹏控,給容器中添加組件,xxxAutoConfigurartion下的xxxxProperties:封裝配置文件中相關(guān)屬性肤寝;