1.SpringBoot的配置文件

SpringBoot使用两种全局配置文件,文件名是固定的。

  • application.properties
  • application.yml

其配置文件的作用就是配置SpringBoot自动配置的默认值,之所以我们只需要一个入口文件就能启动SpringBoot,是因为它已经给我们自动配置好了一些东西,比如端口号等等,如果我们想改变这些配置,就需要用配置文件来说明。

2.YAML简介

它既是一个标记语言,又不是一个标记语言,它以数据为中心,比json、xml更适合做配置文件。比如这里以配置端口号为例,看一下yaml和xml之间的区别:

yaml:

server:
    port:8080

xml

<server>
  <port>8080</port>
</server>

可以看出来yaml配置的方式比xml简介很多,省去了很多的无用标签。

2.1 基本语法

  • k:(空格)v:表示一个键值对,其中冒号后面的空格必须要有
  • 以空格来控制缩进关系,只要是左对齐的一列数据,都是同一个层级的
  • 属性和值都是区分大小写的

2.2 值的写法

  • 字面量:普通的值(数字、字符串、布尔)

    • 字符串不用加引号
    • 双引号不会转义特殊字符,\n表示换行等
    • 单引号会转义特殊字符,也就是写啥样就是啥样
  • 对象:键值对(map)

    • 还是k: v的形式,写法有两种,缩进形式和行内写法

    缩进形式

    yaml friend: zhangsan:14 lisi:20

    行内写法

    yaml friend: {zhangsan: 14, lisi: 20}

  • 数组(List、Set):

    • -值来表示数组中的一个元素

    yaml pets: - cat - pig - dog

    • 用行内写法:

    yaml pets: [cat,dog,pig]

3.获取配置文件中的值(一)

本次我们将会吧yaml中配置的key: value对封装到JavaBean对象中,首先yaml配置文件内容如下:

person:
  lastName: reborn
  age: 20
  boss: true
  birth: 2019/11/14
  maps: {k1: v1, k2: 20}
  lists:
    - cat
    - dog
    - pig
  dog:
    name: heihei
    age: 22

person的实体类是:

package com.eastnotes.springboot.domain;

import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 将配置文件中的每一个属性的值,映射到组件中
 */

@Component
@ConfigurationProperties(prefix = "person")
public class Person implements Serializable {
    private String lastName;
    private Integer age;
    private Boolean boss;
    private Date birth;

    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Boolean getBoss() {
        return boss;
    }

    public void setBoss(Boolean boss) {
        this.boss = boss;
    }

    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<Object> getLists() {
        return lists;
    }

    public void setLists(List<Object> lists) {
        this.lists = lists;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    @Override
    public String toString() {
        return "Person{" +
                "lastName='" + lastName + '\'' +
                ", age=" + age +
                ", boss=" + boss +
                ", birth=" + birth +
                ", maps=" + maps +
                ", lists=" + lists +
                ", dog=" + dog +
                '}';
    }
}

其中,@ConfigurationProperties注解的作用是告诉SpringBoot将本类中所有属性和配置文件的配置进行绑定,prefix属性指定是配置文件中的哪个属性。

另外,如果我们想在yaml中写配置的时候有提示,可以导入一个配置处理器的坐标:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

要想是这个注解起作用,我们需要将其放入到Spring的容器中,因此还需要加上@Component注解

dog的实体类是:

package com.eastnotes.springboot.domain;

import java.io.Serializable;

public class Dog implements Serializable {
    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 +
                '}';
    }
}

然后我们可以在测试文件中进行测试,这里的单元测试用Spring的容器来跑,这样我们就能在测试文件中也是用依赖注入了:

@RunWith(SpringRunner.class)
@SpringBootTest
class SpringBoot02QuickStartApplicationTests {

    @Autowired
    Person person;

    @Test
    void contextLoads() {
        System.out.println(person);
    }
}

运行后的输出结果为:

Person{lastName='reborn', age=20, boss=true, birth=Thu Nov 14 00:00:00 CST 2019, maps={k1=v1, k2=20}, lists=[cat, dog, pig], dog=Dog{name='heihei', age=22}}

另外,如果想让@RunWith生效,还需要导入一下两个依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

PS:如果用Properties文件进行配置,那么形式如下:

person.lastName=张三
person.age=20
person.birth=2019/11/14
person.boss=false
person.maps.k1=v1
person.maps.k2=20
person.list=a,b,c
person.dog.name=dog
person.dog.age=12

但是这样输出之后,会有中文乱码,因此我们需要在IDEA的file encoding中将Transparent native-to-scii conversion配置打上勾。

4.获取配置文件中的值(二)

除了使用@Configurationproperties注解获取配置文件中的值之外,我们还可以使用@Value注解来进行这一操作,@Value是一个值一个值的获取,比如我想获取姓名和年龄的值:

@Value("${person.last-name}")
private String lastName;
@Value("${person.age}")
private Integer age;

可以发现,这种方式获取比较麻烦,需要一个个来写,其实他和@Configurationproperties注解的区别主要如下:

@ConfigurationProperties @Value
功能 批量注入配置文件中的属性 一一配置
松散绑定 支持 不支持
SpEl 不支持 支持
JSR303数据校验 支持 不支持
复杂类型封装 支持 不支持

那我们什么时候用这两者呢?

  • 如果想要在某一业务场景中获取单一属性的值,那么用@Value
  • 其他情况推荐使用@ConfigurationProperties

5.指定配置文件

@PropertySource注解的作用是加载指定配置文件。上面我们使用@ConfigurationProperties@Value来获取配置文件中的内容,之所以能成功是因为他们写在了全局配置文件中,而当我们写在了其他的配置文件中,那么它就获取不到了,此时@PropertySource注解就可以用来指定想要从哪个配置文件中来获取数据了。

@PropertySource(value={"classpath:person.properties"})
public class Person{
  ...
}