SpringBoot: 2.2.1.RELEASE
IDE: IDEA
使用模塊和POM文件
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.demo</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!--Web模塊所需要的依賴啓動器--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--獲取配置文件值所需要的依賴--> <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> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
一、使用@ConfigurationProperties實現獲取
測試文件兩個;
/**
* @Component 表示這個類是springboot的一個組件,只有這個組件在容器中才可以使用
* @ConfigurationProperties 表示這是一個配置類,它的值是通過配置文件獲取的
* prefix 表示獲取的值是這個父節點下的值,這裏獲取的是 person 節點下的值
*/
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String name;
private Integer age;
private Boolean student;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;
private School school;
// getter 、setter 和toString省略
}
public class School {
private String name;
private Date startDate;
// getter 、setter 和toString省略
}
配置文件:
person:
name: Li Ming
age: 12
student: true
birth: 2019/11/14
maps: {k1: v1,k2: v2}
lists: [list1,list2]
school:
name: shuguang
startDate: 2019/09/01
測試類:
@SpringBootTest
class DemoApplicationTests {
@Autowired
Person person;
@Test
void contextLoads() {
System.out.println(person);
}
}
測試結果:
Person{name='Li Ming', age=12, student=true, birth=Thu Nov 14 00:00:00 GMT+08:00 2019, maps={k1=v1, k2=v2}, lists=[list1, list2], school=School{name='shuguang', startDate=Sun Sep 01 00:00:00 GMT+08:00 2019}}
這樣我們就可以獲取到值了
下面我們減少配置文件裏的值
person:
name: Li Ming
# age: 12
student: true
birth: 2019/11/14
maps: {k1: v1,k2: v2}
lists: [list1,list2]
school:
name: shuguang
startDate: 2019/09/01
測試結果:
Person{name='Li Ming', age=null, student=true, birth=Thu Nov 14 00:00:00 GMT+08:00 2019, maps={k1=v1, k2=v2}, lists=[list1, list2], school=School{name='shuguang', startDate=Sun Sep 01 00:00:00 GMT+08:00 2019}}
我們發現,沒有匹配的值這裏會填充 null ;
我們在改一下,把 startDate 寫成 start-date 我們看是否匹配上
person:
name: Li Ming
age: 12
student: true
birth: 2019/11/14
maps: {k1: v1,k2: v2}
lists: [list1,list2]
school:
name: shuguang
start-date: 2019/09/01
測試結果:
Person{name='Li Ming', age=12, student=true, birth=Thu Nov 14 00:00:00 GMT+08:00 2019, maps={k1=v1, k2=v2}, lists=[list1, list2], school=School{name='shuguang', startDate=Sun Sep 01 00:00:00 GMT+08:00 2019}}
我們發現也可以獲取,這說明它的識別是鬆散的 -字母 當成大寫字母處理了
當然,這些在 .properties 中也可以同樣實現
如果 .properties 文件亂碼,按照下面配置
下面是例子
配置文件
person.name=黎明
person.age=12
person.student=true
person.birth=2019/11/14
person.maps.k1=v1
person.maps.k2=v2
person.lists=list1,list2
person.school.name=曙光
person.school.start-date=2019/09/01
測試結果:
Person{name='黎明', age=12, student=true, birth=Thu Nov 14 00:00:00 GMT+08:00 2019, maps={k1=v1, k2=v2}, lists=[list1, list2], school=School{name='曙光', startDate=Sun Sep 01 00:00:00 GMT+08:00 2019}}
這裏發現他們幾乎是可以一樣的使用。
二、使用@Value實現獲取
這個標籤支持三種獲取值的方式,從配置文件獲取只是它的一種方式:
方式 | 例 |
---|---|
通過${配置文件鍵} | @Value("${person.name}") |
通過#{SqEL} spring表達式 | @Value("#{3*4}") |
字面值 | @Value(“true”) |
下面我們改寫一下上面的Person類
@Component
public class Person {
@Value("${person.name}") //通過${配置文件鍵}
private String name;
@Value("#{3*4}") //通過#{SqEL} spring表達式
private Integer age;
@Value("true") //字面值
private Boolean student;
private Date birthDate;
private Map<String,Object> maps;
private List<Object> lists;
private School school;
// getter 、setter 和toString省略
}
測試結果:
Person{name='Li Ming', age=12, student=true, birthDate=null, maps=null, lists=null, school=null}
這樣就可以獲取到了,但是他沒辦法支持鬆散綁定,和當沒有這個配置值時就會報錯
例如 birthDate 在配置文件裏如果是 birth-date 就會報錯,或者配置文件的鍵不存在也會報錯,而不是填充 null ;
三、對比
我們修改一下Person類
@Component
@Validated
public class Person {
@Email
@Value("${person.name}") //通過${配置文件鍵}
private String name;
@Value("#{3*4}") //通過#{SqEL} spring表達式
private Integer age;
@Value("true") //字面值
private Boolean student;
private Date birthDate;
private Map<String,Object> maps;
private List<Object> lists;
private School school;
// getter 、setter 和toString省略
}
測試結果:
Person{name='Li Ming', age=12, student=true, birthDate=null, maps=null, lists=null, school=null}
我們發現JSR303沒有校驗住
我們改成@ConfigurationProperties的方式
@Component
@ConfigurationProperties(prefix = "person")
@Validated
public class Person {
@Email
private String name;
private Integer age;
private Boolean student;
private Date birthDate;
private Map<String,Object> maps;
private List<Object> lists;
private School school;
// getter 、setter 和toString省略
}
運行結果
//省略
Caused by: org.springframework.boot.context.properties.bind.validation.BindValidationException: Binding validation errors on person
- Field error in object 'person' on field 'name': rejected value [Li Ming]; codes [Email.person.name,Email.name,Email.java.lang.String,Email]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [person.name,name]; arguments []; default message [name],[Ljavax.validation.constraints.Pattern$Flag;@ddf20fd,.*]; default message [不是一個合法的電子郵件地址]; origin class path resource [application.yml]:2:9
//省略
從測試結果我們可以看出它是支持的
我們看一下複雜類型的注入
@ConfigurationProperties是支持的,上面map和對象的注入就是個例子
@Value不支持,舉例說明:
@Component
public class Person {
@Value("${person.name}") //通過${配置文件鍵}
private String name;
@Value("#{3*4}") //通過#{SqEL} spring表達式
private Integer age;
@Value("true") //字面值
private Boolean student;
private Date birthDate;
@Value("${person.maps}")
private Map<String,Object> maps;
private List<Object> lists;
private School school;
// getter 、setter 和toString省略
}
測試結果:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'person': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'person.maps' in value "${person.maps}"
我們發現報錯了。也驗證了@Value不支持複雜類型的注入
歸納:
@ConfigurationProperties | @Value | |
---|---|---|
配置文件注入方式 | 批量注入 | 一個一個注入 |
配置文件不存在值 | 用null填充 | 報錯,不允許 |
SpEL | 不支持 | 支持 |
鬆散綁定 | 支持 | 不支持 |
JSR303校驗 | 支持 | 不支持 |
配置文件複雜類型注入 | 支持 | 不支持 |