SpringBoot——實現獲取配置文件裏的配置值

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校驗 支持 不支持
配置文件複雜類型注入 支持 不支持
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章