欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SpringBoot——实现获取配置文件里的配置值

程序员文章站 2022-05-03 22:29:14
...

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 文件乱码,按照下面配置
SpringBoot——实现获取配置文件里的配置值

下面是例子

配置文件

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校验 支持 不支持
配置文件复杂类型注入 支持 不支持