SpringBoot之配置
回顧:
配置檔案
① 兩種全域性配置檔案(檔名是固定的)
配置檔案放在src/main/resources目錄或者類路徑/config下
application.properties(優先順序高)
application.yml / application.yaml
配置檔案的作用: 修改SpringBoot自動配置的預設值
② YAML
yml / yaml是YAML(YAML Ain't Markup Language)語言的檔案, YAML以資料為中心, 比json/xml等更適合做配置檔案.
例項:
YAML的基本語法
- 使用縮排表示層級關係
- 縮排時不允許使用tab鍵, 只允許使用空格
- 縮排的空格數目不受限制, 只要相同層級的元素在左側對齊即可
- 大小寫敏感
YAML支援的三種資料結構
- 物件 / Map(屬性和值): 鍵值對的集合
普通寫法:
friends:
lastName: zhangsan
age: 20
行內寫法:
friends: {lastName: zhangsan,age: 20}
- 陣列: 一組按次序排列的值
用- 值表示陣列中的一個元素
普通寫法:
pets:
- cat
- pig
- dog
行內寫法:
pets: [cat,pig,dog]
- 字面量(普通的值, 如: 數字 字串 布林): 單個的 / 不可再分的值
直接寫: 字串預設不用加單引號或雙引號
"": 雙引號不會轉義字串裡面的特殊字元, 特殊字元會作為其本身的意義輸出
如: name: 'zhangsan \n lisi' ==> 代表為 zhangsan 換行 lisi
'': 單引號會轉義字串裡面的特殊字元, 特殊字元不會作為其本身的意義輸出(特殊字元最終只是一個普通的字串)
如: name: 'zhangsan \n lisi' ==> 代表為 zhangsan \n lisi
③ 例項測試
實體類:
Person:
private String name;
private Integer age;
private Boolean boss;
private Date birth;
private Map<String, Object> maps;
private List<Object> lists;
private Dog dog;
Dog:
private String name;
private Integer age;
配置檔案(application.yml):
將配置檔案中的每個值對映到屬性中:
在Person類上加入以下兩個註解:
@Component //將該元件初始化到容器中, 才能使用@ConfigurationProperties註解的功能
@ConfigurationProperties(prefix = "person") //該註解指定配置檔案(全域性配置檔案application.yml / application.properties)中具體哪個變數下的值進行一一對映
注: 可以先匯入配置檔案處理器, 這樣在編寫配置檔案時會有相應的提示
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
測試:
@Autowired
Person person;
@Test
public void contextLoads() {
System.out.println(person);
}
測試結果:
配置檔案(application.properties):
測試結果:
另一種獲取配置檔案的值的方式(@Value("字面量 / ${key} / #{SpEL表示式}")):
測試結果:
@ConfigurationProperties和@Value的區別:
@ConfigurationProperties | @Value | |
功能 | 批量注入配置檔案中的屬性 | 一個個指定 |
鬆散繫結(鬆散語法) | 支援(如: first-name和firstName相同) | 不支援(只支援first-name) |
SpEL表示式 | 不支援 | 支援(如: #{2.3*10}) |
JSR303資料校驗(在類上使用@Validated註解) | 支援(如: 在某個欄位上使用@Email註解, 則該欄位必須為郵箱格式才正確, 否則報錯) |
不支援 |
複雜型別封裝 | 支援(如: 取Map或List或物件中的值) | 不支援 |
資料校驗格式:
小結:
如果只是在某個業務邏輯中需要獲取一下配置檔案中的某項或某幾項值, 則使用@Value註解; 如果專門編寫了一個javaBean來和配置檔案進行對映, 此時則需要@ConfigurationProperties註解.
從非全域性配置檔案中獲取值進行對映的註解:
1) @ PropertySource(value={"配置檔案的路徑",...})
將之前的屬性值都移到person.properties檔案中, 測試能否將值注入Person類下的屬性內.
2) @ImportResource: 匯入Spring的配置的檔案, 讓配置檔案的內容生效
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.idea.springbott.service.HelloService"></bean>
</beans>
HelloService:
@Autowired
ApplicationContext ac;
@Test
public void testHelloService(){
boolean b = ac.containsBean("helloService");
System.out.println(b);
}
SpringBoot推薦給容器中新增元件的方式: 全註解方式
① 配置類<====>配置檔案
② @Bean註解: 類同於配置檔案中的<bean></bean>標籤, 意為將方法的返回值新增到容器中
MyConfig配置類:
@Configuration
public class MyAppConfig {
@Bean
public HelloService helloService(){
System.out.println("配置類給容器新增元件了...");
return new HelloService();
}
}
配置檔案佔位符:
① 隨機數
${random.value} / ${random.int} / ${random.long} / ${random.int(10)} / ${random.int[1024, 65536]}
② 佔位符獲取之前的屬性值, 如果沒有則可以指定預設值
屬性配置:
person.name=王五${random.uuid}
person.age=${random.int}
person.boss=true
person.birth=2018/12/07
person.maps.k1=v1
person.maps.k2=15
person.lists=a,b,c
person.dog.name=${person.name:此處填寫預設值}的dog
person.dog.age=18
profile標識: 動態切換, 以便適應不同的環境(開發環境 / 測試環境 / 生產環境等)
啟用方式
1) spring.profiles.active=[具體的profile的名稱]
2) 命令列: 打包成jar, 利用控制檯方式啟動(java -jar [部署包的名稱] --spring.profiles.active=[profile的名稱])
或者在idea中的Edit Configurations中進行設定也是屬於命令列的一種方式
3) 虛擬機器引數(VM options): -Dspring.profiles.active=[profile的名稱]
① .properties檔案的切換方式
在主配置檔案編寫的時候, 檔名可以是 application-[profile標識].properties/yml
如: application-dev.properties(表示開發環境) / application-prod.properties(表示生產環境)
預設情況下使用application.properties / application.yml主配置檔案, 如果需要切換環境配置檔案, 需要在主配置檔案裡面啟用該需要切換的配置檔案, 如: spring.profiles.active=[profile標識]
spring.profiles.active=dev
② .yml檔案的切換方式(文件塊)
內部配置檔案的載入順序:
4個存放位置: 按照優先順序從高到低排列, 高優先順序的配置覆蓋低優先順序的配置
① file: /config/ ==> 當前專案下的config資料夾下 優先順序最高
② file: / ==> 當前專案下 優先順序第二
③ classpath: /config/ ==> classpath下的config資料夾下 優先順序第三
④ classpath: / ==> classpath下 優先順序第四
SpringBoot會從這四個位置全部載入主配置檔案從而互補配置
通過spring.config.location來改變預設的配置檔案的位置
① 打包專案
② 使用命令列引數的形式, 在啟動專案的時候指定配置檔案的新位置, 指定的配置檔案會和預設載入的配置檔案共同起作用形成互補配置
外部配置檔案的載入順序:
SpringBoot也可以從以下位置載入配置檔案, 優先順序由高到低, 高優先順序的配置會覆蓋低優先順序的配置, 所有的配置會形成互補配置.
① 命令列引數
java -jar [jar包名] --server.port=8089 / 其他命令也行(多個引數用空格隔開).
優先載入帶spring.profiles.active, 並且由外部向內部載入(外部的優先順序比內部的高)
② jar包外部的application-[profile的名稱].properties / .yml(帶spring.profiles.active)配置檔案
③ jar包內部的application-[profile的名稱].properties / .yml(帶spring.profiles.active)配置檔案
再載入不帶spring.profile, 並且由外部向內部載入(外部的優先順序比內部的高)
④ jar包外部application-[profile的名稱].properties / .yml(不帶spring.profiles.active)配置檔案
⑤ jar包內部application-[profile的名稱].properties / .yml(不帶spring.profiles.active)配置檔案
⑥ @Configuration註解類上的@PropertySource指定配置檔案
自動配置原理:
配置檔案能配置的屬性
1) SpringBoot啟動的時候載入主配置類, 開啟了自動配置功能(註解: @EnableAutoConfiguration)
2) @EnableAutoConfiguration的作用:
利用@Import({EnableAutoConfigurationImportSelector.class})給容器中匯入一些元件
selectImports(AnnotationMetadata annotationMetadata) ==> List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes); //獲取候選項的配置
① SpringFactoriesLoader.loadFactoryNames()
② classLoader.getResources("META-INF/spring.factories") //掃描所有jar包類路徑下的META-INF/spring.factories
把掃描到的內容封裝成properties物件, 並從中取出EnableAutoConfiguration.class類對應的值, 最後把它們新增進容器中.
每一個xxxAutoConfiguration都是容器中的一個元件, 都加入到容器中, 用他們來做自動配置.
3) 每一個自動配置類進行自動配置功能
4) 舉例: HttpEncodingAutoConfiguration(http編碼的自動配置)
@Configuration //這是一個配置類
@EnableConfigurationProperties({HttpEncodingProperties.class}) //啟動指定類的ConfigurationProperties的功能; 將配置檔案中對應的值和HttpEncodingProperties繫結起來;
@ConditionalOnWebApplication //Spring底層有@Conditional註解, 根據不同的條件, 如果滿足指定的條件, 整個配置類才會生效.(判斷當前應用是否是web應用, 如果是: 當前配置類生效)
@ConditionalOnClass({CharacterEncodingFilter.class}) //判斷當前專案是否有CharacterEncodingFilter類
CharacterEncodingFilter: 是SpringMVC中進行亂碼解決的過濾器
@ConditionalOnProperty(prefix = "spring.http.encoding", value = {"enabled"}, matchIfMissing = true) //判斷配置檔案中是否存
在某個配置, 即: spring.http.encoding.enabled; matchIfMissing = true: 如果檔案不存在, 判斷也是成立的(也就是說, 即使不配
置spring.http.encoding.enabled=true, 也是預設生效的)
HttpEncodingAutoConfiguration類下:
所有在配置檔案中能配置的屬性都是在xxxProperties類中封裝著
HttpEncodingProperties: 該類上標註了@ConfigurationProperties(prefix = "spring.http.encoding")註解
該註解從配置檔案中獲取指定的值和bean的屬性進行繫結
所以, HttpEncodingAutoConfiguration這個類的意義就是根據當前不同的條件進行判斷, 決定這個配置類是否生效.
一旦這個配置類生效, 這個配置類就會給容器中新增各種元件, 這些元件的屬性是從對應的properties類中獲取的, 而這些類裡面每一個屬性又是和配置檔案繫結的.
總結:
① SpringBoot啟動會載入大量的自動配置類
② 檢視需要的功能有沒有SpringBoot預設寫好的自動配置類
③ 如果有, 這個配置類配置了哪些元件(需要則注入即可, 無需再配置), 如果沒有, 則需要自己寫配置類
④ 給容器中的自動配置類新增元件的時候, 會從properties類中獲取某些屬性, 就可以在配置檔案中指定這些屬性的值(跟配置檔案綁定了)
附:
由於自動配置類必須在一定條件下才能生效, 所以可以通過在配置檔案中啟用debug=true屬性, 讓控制檯列印自動配置報告, 即能很方便知道具體哪些配置類生效哪些配置類不生效.