SpringBoot【二】 SpringBoot 配置
SpringBoot 配置
配置檔案
SpringBoot 使用一個全域性的配置檔案,配置檔名稱是固定的,作用是修改 SpringBoot 自動配置的預設值(底層自動配置的值),有兩種方式可以使用:
-
application.properties
-
- 語法結構 :
key=value
- 語法結構 :
-
application.yaml【推薦使用】
-
- 語法結構 :
key:空格value
- 語法結構 :
比如可以在配置檔案中修改 Tomcat 預設啟動的埠號
server.port=8081
yaml
YAML是 "YAML Ain't a Markup Language" (YAML不是一種標記語言)的遞迴縮寫。在開發的這種語言時,YAML 的意思其實是:"Yet Another Markup Language"(仍是一種標記語言)
這種語言以資料作為中心,而不是以標記語言為重點!
1、yaml 和 xml
以前的配置檔案,大多數都是使用xml來配置
-
傳統 xml 配置:
<server> <port>8081<port> </server>
-
yaml 配置:
server: prot: 8080
2、基礎語法
語法要求嚴格
-
空格不能省略;
-
以縮排來控制層級關係,只要是左邊對齊的一列資料都是同一個層級的;
-
屬性和值的大小寫都是十分敏感的。
-
字面量:普通的值 [ 數字,布林值,字串 ]
字面量直接寫在後面就可以,字串預設不用加上雙引號或者單引號
k: v
注意:
-
“ ” 雙引號,不會轉義字串裡面的特殊字元,特殊字元會作為本身想表示的意思
比如:name: "zhang \n san" 輸出 :zhang 換行 san
-
'' 單引號,會轉義特殊字元,特殊字元最終會變成和普通字元一樣輸出
比如 :name: ‘zhang \n san’ 輸出 :zhang \n san
-
-
物件、Map(鍵值對)
#物件、Map格式 k: v1: v2:
在下一行來寫物件的屬性和值的關係,注意縮排
student: name: zhangsan age: 3 # 行內寫法 student: {name: zhangsan,age: 3}
-
陣列( List、set )
用 - 值表示陣列中的一個元素,比如:
pets: - cat - dog - pig # 行內寫法 pets: [cat,dog,pig]
注入配置檔案
1、yaml 配置檔案注入
yaml 檔案強大的地方在於,它可以給我們的實體類直接注入匹配值。
-
在 springboot 專案的 resources 目錄下新建一個檔案 application.yml
-
編寫一個實體類 Dog
-
原來 Spring 中給 bean 注入屬性值,通過 @Value
@Component //註冊bean到容器中 public class Dog { @Value("旺財") private String name; @Value("3") private int age; ...//有參無參構造、get、set方法、toString()方法 }
-
SpringBoot 的測試類下注入 Dog 物件並輸出
@SpringBootTest class Springboot02ConfigApplicationTests { @Autowired // 自動注入 private Dog dog; @Test void contextLoads() { System.out.println(dog); // 輸出結果:Dog{name=旺財, age=3} } }
-
編寫一個複雜一點的實體類:Person 類
@Component //註冊 bean 到容器中 public class Person { private String name; private int age; private boolean happy; private Date birth; private Map<String,Object> maps; private List<Object> lists; private Dog dog; ... //有參無參構造、get、set方法、toString()方法 }
-
使用 yaml 配置的方式進行注入,編寫 application.yml
person: name: zhangsan age: 3 happy: true birth: 2020/02/02 maps: {k1: v1,k2: v2} lists: - code - music - dance dog: name: wangcai age: 3
-
注入到 Person 類中
@Component @ConfigurationProperties(prefix = "person") public class Person { ... // 不變 }
@ConfigurationProperties 作用:
將配置檔案中配置的每一個屬性的值,對映到這個元件中,告訴 SpringBoot 將本類中的所有屬性和配置檔案中相關的配置進行繫結,其中引數 prefix = “person” 表示將與配置檔案中的 person 下面的所有屬性一一對應。
-
標註 @ConfigurationProperties 註解後,IDEA 提示報紅(但是不影響程式執行),SpringBoot 配置註解處理器沒有找到,檢視文件,找到一個依賴
<!-- 匯入配置檔案處理器,配置檔案進行繫結就會有提示,需要重啟 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
-
測試類中測試
@SpringBootTest class Springboot02ConfigApplicationTests { @Autowired private Person person; @Test void contextLoads() { System.out.println(person); }
-
輸出 Person 物件,屬性值和 yaml 注入的相同,說明所有值全部注入成功
Person{name='zhangsan', age=3, happy=true,birth=Sun Feb 02 00:00:00 GMT+08:00 2020,maps={k1=v1, k2=v2}, lists=[code, music, dance],dog=Dog{name='wangcai', age=3}}
注意:當配置檔案的 key 值和屬性的值設定的不一樣時,結果輸出為 null,注入失敗。
配置檔案佔位符:配置檔案可以編寫佔位符生成隨機數
person:
name: zhangsan${random.uuid} # 隨機uuid
age: ${random.int} # 隨機int
happy: true
birth: 2020/02/02
maps: {k1: v1,k2: v2}
lists:
- code
- music
- dance
dog:
name: ${person.hello:other}_wangcai
age: 3
2、properties 配置檔案注入(載入指定的配置檔案)
properties 配置檔案在寫中文的時候,會有亂碼,需要去 IDEA 中(settings --> FileEncodings)設定編碼格式為UTF-8。
@PropertySource :載入指定的配置檔案
@configurationProperties:預設從全域性配置檔案中獲取值
-
在 resources 目錄下新建一個 person.properties 檔案
name=lisi
-
然後在 Person 類中指定載入 person.properties 檔案
@Component // 載入指定的配置檔案 @PropertySource(value = "classpath:application.properties") public class Person { //直接使用@value // @Value("男") // 字面量 // @Value("#{9*2}") // #{SPEL} Spring表示式 @Value("${name}") // spring EL表示式取出配置檔案的值 private String name; private int age; ... }
-
測試輸出,Person 物件中只有 name 屬性被賦值為 lisi,其他都為 null,說明配置檔案繫結成功。
Person{name='lisi', age=null, happy=null, birth=null, maps=null, lists=null, dog=null}
注意:@Value 使用起來並不友好,因為我們需要為每個屬性單獨註解賦值,比較麻煩
3、兩種方式對比
-
@ConfigurationProperties 只需要寫一次即可, @Value 則需要每個欄位都新增
-
鬆散繫結:比如 yml 中寫的 last-name,和實體類中的 lastName 一樣, - 後面跟著的字母預設是大寫的。
-
JSR303 資料校驗 , 可以在欄位上增加一層過濾器驗證,可以保證資料的合法性
-
複雜型別封裝,yml 中可以封裝物件 , 使用 value 就不支援
結論:
-
配置 yml 和配置 properties 都可以獲取到值 , 強烈推薦 yml;
-
如果在某個業務中,只需要獲取配置檔案中的某個值,可以使用一下 @value;
-
如果專門編寫了一個 JavaBean 來和配置檔案進行一一對映,使用 yaml 和 @configurationProperties。
JSR303 資料校驗
Springboot 中可以用 @validated 來校驗資料,如果資料異常則會統一丟擲異常,方便異常中心統一處理。使用資料校驗,可以保證資料的正確性。
在 Person 類中加入註解讓 name 只能支援 Email 格式;
@Component
@ConfigurationProperties(prefix = "person")
@Validated // 資料校驗
public class Person {
@Email(message = "郵箱格式錯誤") //name必須是郵箱格式
private String name;
...
}
執行結果:default message [不是一個合法的電子郵件地址];
常見引數:
@NotNull(message="名字不能為空")
private String userName;
@Max(value=120,message="年齡最大不能查過120")
private int age;
@Email(message="郵箱格式錯誤")
private String email;
空檢查
@Null 驗證物件是否為null
@NotNull 驗證物件是否不為null, 無法查檢長度為0的字串
@NotBlank 檢查約束字串是不是Null還有被Trim的長度是否大於0,只對字串,且會去掉前後空格.
@NotEmpty 檢查約束元素是否為NULL或者是EMPTY.
Booelan檢查
@AssertTrue 驗證 Boolean 物件是否為 true
@AssertFalse 驗證 Boolean 物件是否為 false
長度檢查
@Size(min=, max=) 驗證物件(Array,Collection,Map,String)長度是否在給定的範圍之內 @Length(min=, max=) string is between min and max included.
日期檢查
@Past 驗證 Date 和 Calendar 物件是否在當前時間之前
@Future 驗證 Date 和 Calendar 物件是否在當前時間之後
@Pattern 驗證 String 物件是否符合正則表示式的規則
.......等等除此以外,我們還可以自定義一些資料校驗規則
多環境切換
profile 是 Spring 對不同環境提供不同配置功能的支援,可以通過啟用不同的環境版本,實現快速切換環境。
1、多配置檔案
在主配置檔案編寫的時候,檔名可以是 application-{profile}.properties/yml , 用來指定多個環境版本
例如:
- application-test.properties 代表測試環境配置
- application-dev.properties 代表開發環境配置
但是 Springboot 並不會直接啟動這些配置檔案,它預設使用 application.properties主配置檔案,需要通過一個配置來選擇需要啟用的環境:
#比如在配置檔案中指定使用dev環境,我們可以通過設定不同的埠號進行測試;
#我們啟動SpringBoot,就可以看到已經切換到dev下的配置了;
spring.profiles.active=dev
2、yaml 的多文件塊
和 properties 配置檔案中一樣,但是使用 yml 去實現不需要建立多個配置檔案,更加方便。
server:
port: 8081
#選擇要啟用那個環境塊
spring:
profiles:
active: prod
---
server:
port: 8083
spring:
profiles: dev #配置環境的名稱
---
server:
port: 8084
spring:
profiles: prod #配置環境的名稱
注意:如果 yml 和 properties 同時都配置了埠,並且沒有啟用其他環境,預設會使用 properties 配置檔案。
配置檔案載入位置
官方文件說明,外部配置檔案位置有:
-
file:./config/
-
file:./
-
classpath:./config/
-
classpath:./
SpringBoot 啟動會掃描以下位置的 application.properties 或者 application.yml 檔案作為 SpringBoot 的預設配置檔案,優先順序由高到底,高優先順序的配置會覆蓋低優先順序的配置:
優先順序1:專案路徑(file)下的config資料夾配置檔案
優先順序2:專案路徑下配置檔案
優先順序3:資源路徑(classpath)下的config資料夾配置檔案
優先順序4:資源路徑下配置檔案
SpringBoot 會從這四個位置全部載入主配置檔案,互補配置。
指定位置載入配置檔案:
可以通過 spring.config.location 來改變預設的配置檔案位置,專案打包好以後,可以使用命令列引數的形式,啟動專案的時候來指定配置檔案的新位置,這種情況,一般是後期運維做的多,相同配置,外部指定的配置檔案優先順序最高
java -jar spring-boot-config.jar --spring.config.location=F:/application.properties
自動配置原理
關注兩種檔案:
-
xxxAutoConfiguration:自動配置類,給容器中新增元件
-
xxxProperties :預設屬性類,封裝配置檔案中相關屬性,和配置檔案繫結,這樣就可以使用自定義的配置
原理分析:
以 HttpEncodingAutoConfiguration
(Http編碼自動配置)和 ServerProperties
為例:
// 表示這是一個配置類,和以前編寫的配置檔案一樣,也可以給容器中新增元件
@Configuration(proxyBeanMethods = false)
// 自動配置屬性:ServerProperties
//進入這個ServerProperties檢視,將配置檔案中對應的值和ServerProperties繫結起來;
//並把ServerProperties加入到ioc容器中
@EnableConfigurationProperties(ServerProperties.class)
//Spring底層@Conditional註解
//根據不同的條件判斷,如果滿足指定的條件,整個配置類裡面的配置就會生效;
//這裡的意思就是判斷當前應用是否是web應用,如果是,當前配置類生效
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
//判斷當前專案有沒有這個類CharacterEncodingFilter:SpringMVC中進行亂碼解決的過濾器
@ConditionalOnClass(CharacterEncodingFilter.class)
//判斷配置檔案中是否存在某個配置:server.servlet.encoding
//如果不存在,判斷也是成立的
//即使我們配置檔案中不配置 server.servlet.encoding=true,也是預設生效的;
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
//它已經和SpringBoot的配置檔案映射了
private final Encoding properties;
//只有一個有參構造器的情況下,引數的值就會從容器中拿
public HttpEncodingAutoConfiguration(ServerProperties properties) {
this.properties = properties.getServlet().getEncoding();
}
//給容器中新增一個元件,這個元件的某些值需要從properties中獲取
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE));
return filter;
}
...
}
//從配置檔案中獲取指定的值和 bean 的屬性進行繫結
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
...
}
總結:
根據當前不同的條件判斷,決定這個配置類是否生效;一旦這個配置類生效,這個配置類就會給容器中新增各種元件;這些元件的屬性是從對應的 properties 類中獲取的,這些類裡面的每一個屬性又是和配置檔案繫結的;
所有在配置檔案中能配置的屬性都是在 xxxxProperties 類中封裝著,配置檔案能配置什麼就可以參照某個功能對應的這個屬性類。
精髓:
- SpringBoot 啟動會載入大量的自動配置類
- 看我們需要的功能有沒有在 SpringBoot 預設寫好的自動配置類當中;
- 再來看這個自動配置類中到底配置了哪些元件(只要需要用的元件存在其中,我們就不需要再手動配置)
- 給容器中自動配置類新增元件的時候,會從 properties 類中獲取某些屬性,我們只需要在配置檔案中指定這些屬性的值即可。
@Conditional
自動配置類必須在一定的條件下才能生效,主要原因是每個自動配置類上都添加了 @Conditional 的派生註解。
Spring 註解版原生的 @Conditional 作用:必須是 @Conditional 指定的條件成立,才給容器中新增元件,配置裡面的所有內容才生效。
問題:如何知道哪些自動配置類生效?
通過啟用 debug=true 屬性,來讓控制檯列印自動配置報告,這樣知道哪些自動配置類生效
#開啟springboot的除錯類
debug=true
輸出日誌中將配置類分為三種:
-
Positive matches:(自動配置類啟用的:正匹配)
-
Negative matches:(沒有啟動,沒有匹配成功的自動配置類:負匹配)
-
Unconditional classes: (沒有條件的類)