第二章 Spring Boot 配置
1、YAML 配置
SpringBoot 全局配置檔案
application.properties
application.yml
YAML 以資料為中心,比 json、xml 更适合作為配置檔案
server:
port: 8081
<server>
<port>8081</port>
</server>
2、YAML 文法
https://yaml.org/YAML 語言教程:
http://www.ruanyifeng.com/blog/2016/07/yaml.html1、基本文法
key:空格value
- 空格縮進來控制層級關系,左對齊的資料就是一個層級
- 屬性和值大小寫敏感
- 空格必須有
2、值的寫法
2.1、字面量:普通的值(數字,字元串,布爾)
字元串預設不用加單引号或者雙引号
(1)""雙引号不會轉義特殊字元。特殊字元會作為本身想表達的意思
eg:
name: "張三\n李四"
輸出:
張三[換行]
李四
2.2、對象,map(屬性和值,鍵值對)
(1)普通寫法
person:
name: Tom
age: 23
(2)行内寫法
person: { name: Tom, age: 23 }
2.3、數組,(List, Set)
pets:
- cat
- dog
- pig
pets: [cat, dog, pig]
3、YAML 配置檔案中值擷取
配置檔案
src/main/resources/application.yml
person:
lastName: Tom
age: 18
boss: false
birth: 2017/12/12
maps: { k1: v1, k2: v2 }
lists:
- cat
- dog
dog:
name: Jack
age: 2
映射類
src/main/java/com/mouday/bean/Person.java
package com.mouday.bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 将配置檔案中的屬性映射到這個元件中
*/
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String name;
private Integer age;
private Boolean sex;
private Date birth;
private Map<String, Object> maps;
private List<String> lists;
private Dog dog;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Boolean getSex() {
return sex;
}
public void setSex(Boolean sex) {
this.sex = sex;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public Map<String, Object> getMaps() {
return maps;
}
public void setMaps(Map<String, Object> maps) {
this.maps = maps;
}
public List<String> getLists() {
return lists;
}
public void setLists(List<String> lists) {
this.lists = lists;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
", birth=" + birth +
", maps=" + maps +
", lists=" + lists +
", dog=" + dog +
'}';
}
}
src/main/java/com/mouday/bean/Dog.java
package com.mouday.bean;
public class Dog {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
單元測試依賴
pom.xml
<!--配置檔案處理器 導入配置檔案導入提示-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
單元測試
src/test/java/com/mouday/DemoApplicationTests.java
package com.mouday;
import com.mouday.bean.Person;
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;
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
@Autowired
private Person person;
@Test
public void contextLoads() {
System.out.println(person);
}
}
列印結果
Person{name='Tom', age=18, sex=false, birth=Tue Dec 12 00:00:00 CST 2017,
maps={k1=v1, k2=v2},
lists=[cat, dog],
dog=Dog{name='Jack', age=2}
}
讀取 properties 檔案配置
src/main/resources/application.properties
person.name=TOM
person.age=18
person.sex=false
person.birth=2017/12/12
person.maps.k1=v1
person.maps.k2=v2
person.lists=cat,dog
person.dog.name=Jack
person.dog.age=2
4、@ConfigurationProperties 與@Value 差別
@ConfigurationProperties | @Value | |
功能 | 批量注入配置檔案中的屬性 | 一個一個指定 |
松散綁定 | 支援 | 不支援 |
SpEL | ||
JSR303 資料校驗 | ||
複雜類型封裝 |
屬性名比對規則
person.firstName
person.first-name
person.first_name
PERSON_FIRST_NAME
package com.mouday.bean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 将配置檔案中的屬性映射到這個元件中
*/
@Component
// @ConfigurationProperties(prefix = "person")
public class Person {
/**
* <bean class="Person">
* <property name="name" value="Tom" />
* </bean>
*
* value 支援
* 字面量
* ${key}從環境變量,配置檔案中擷取值
* #{SpEL}表達式
*/
@Value("Tom")
private String name;
@Value("#{12*2}")
private Integer age;
@Value("true")
private Boolean sex;
@Value("${person.birth}")
private Date birth;
private Map<String, Object> maps;
private List<String> lists;
private Dog dog;
/**
* 略setter/getter toString()
*/
}
Person{name='Tom', age=24, sex=true, birth=Tue Dec 12 00:00:00 CST 2017,
maps=null, lists=null, dog=null}
配置檔案注入值資料校驗
import org.hibernate.validator.constraints.Email;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
@Component
@ConfigurationProperties(prefix = "person")
@Validated
public class Person {
@Email
private String name;
}
使用方式
- 隻是在某個業務邏輯中擷取一個配置檔案中的某項值,使用@Value
- 專門編寫一個 javaBean 來映射配置檔案,那麼使用@ConfigurationProperties
@Value 用法示例
package com.mouday.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@Controller
@RestController
public class HelloController {
@Value("${person.name}")
private String name;
@RequestMapping("/hello")
@ResponseBody
public String hello(){
return "Hello world! " + this.name;
}
}
5、@PropertySource、@ImportResource、@Bean
@ConfigurationProperties 預設加載全局配置
5.1、@PropertySource 加載指定配置檔案
import org.springframework.stereotype.Component;
import org.springframework.context.annotation.PropertySource;
@Component
// @ConfigurationProperties(prefix = "person")
@PropertySource(value = {"classpath:person.properties"})
public class Person {}
5.2、@ImportResource 導入 Spring 配置檔案
src/main/resources/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 name="dog" class="com.mouday.bean.Dog"/>
</beans>
@ImportResource 标注在配置類上
package com.mouday;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;
@ImportResource(value = {"classpath:beans.xml"})
@SpringBootApplication
public class ApplicationMain {
public static void main(String[] args) {
SpringApplication.run(ApplicationMain.class, args);
}
}
測試方法
package com.mouday;
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.context.ApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
@Autowired
private ApplicationContext context;
@Test
public void TestDog(){
System.out.println(this.context.containsBean("dog"));
}
}
5.3、@Bean 用于配置類中給容器添加元件
package com.mouday.config;
import com.mouday.bean.Dog;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Configuration 指明目前類是一個配置類
* 替代Spring的配置檔案
*/
@Configuration
public class MyConfig {
// 将方法的傳回值添加到容器,容器中元件預設id是方法名
@Bean
public Dog dog(){
return new Dog();
}
}
Spring 推薦使用全注解方式給容器添加元件
6、配置檔案占位符
RandomValuePropertySource 配置檔案中可以使用随機數
${random.value}
${random.int}
${random.uuid}
${random.long}
${random.int(10)}
${random.int[1024,65536]}
屬性配置占位符
app.name=MyApp
app.description=${app.name:預設值}
7、Profile 多環境支援
Profile 對不同環境提供不同配置功能的支援
1、多 Profile 檔案
application-{profile}.properties
預設使用
application.properties
通過 spring.profiles.active=prod 指定配置檔案
server.port=8080
spring.profiles.active=prod
application-dev.properties
server.port=8081
application-prod.properties
server.port=8082
2、yaml 文檔塊模式
application.yml
server:
port: 8080
spring:
profiles:
active: dev
---
server:
port: 8081
spring:
profiles: dev
---
server:
port: 8082
spring:
profiles: prod
8、配置檔案的加載位置
Spring Boot 會自動掃描一下位置的
application.properties 或者 application.yml 檔案作為配置檔案
優先級從高到低,所有檔案都被加載,
互補配置:高優先級覆寫低優先級
./config/
./
classpath:/config/
classpath:/
spring.config.location 修改預設位置
9、外部配置加載順序
優先級從高到低如下
1. 指令行參數
$ java -jar springboot-helloword-1.0-SNAPSHOT.jar --server.port=8005
2. java:comp/env的JNDI屬性
3. java系統屬性System.getProperties()
4. 作業系統環境變量
5. RandomValuePropertySource配置的random.*屬性
6. jar包外部的application-{profile}.properties或application.yml(帶spring.profile)配置檔案
7. jar包内部的application-{profile}.properties或application.yml(帶spring.profile)配置檔案
8. jar包外部的application.properties或application.yml(不帶spring.profile)配置檔案
9. jar包内部的application.properties或application.yml(不帶spring.profile)配置檔案
10. @Configuration注解類上的@PropertySource
11. 通過SpringApplication.setDefualtProperties指定的預設屬性
總結:
- 高優先級配置會覆寫低優先級配置
- 所有配置會形成互補配置
10、自動配置原理
掃描配置檔案内容包裝成 properties 對象
将配置内容加載到容器中
- AutoConfiguration 自動配置類
- Properties 封裝屬性
- @Condition 判斷條件成立,決定配置類是否生效
11、@Conditional&自動配置報告
@ConditionalOnJava
@ConditionalOnMissingBean
@ConditionalOnClass
..
自動配置類必須在一定的條件下才生效
開啟調試模式
debug=true
列印自動配置報告
=========================
AUTO-CONFIGURATION REPORT
=========================
Positive matches: 啟動的自動配置類
Negative matches: 沒啟用啟動的自動配置類
Exclusions:
Unconditional classes: