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