详解SpringBoot配置文件&YAML配置注入

详解SpringBoot配置文件&YAML配置注入

一、SpringBoot配置文件

1. SpringBoot默认配置文件

  • SpringBoot使用默认的全局的配置文件:application.properties/application.yml
  • 配置文件名固定是是application
`application.properties`
	语法结构: key=value

`application.yml`
	语法结构: key:空格 value

2. 配置文件的作用

SpringBoot在底层给我们自动做了一些配置,所以springboot项目不编写配置文件也可以正常运行,但是根据我们的具体开发我们需要修改SpringBoot自动配置的默认值;

比如我们可以更改默认启动的端口号

application.properties中添加

#更改项目端口号
server.port=8081

然后重新启动,可以看到启动的端口号变更
image-20200918004521582
然后访问localhost:8081 即可
image-20200918004714066

3. 配置文件的位置

springboot启动会扫描以下位置的application.properties/application.yml文件作为其默认配置文件:

优先级1:项目路径下的config文件夹配置文件
优先级2:项目路径下配置文件
优先级3:资源路径下的config文件夹配置文件
优先级4:资源路径下配置文件

可以发现:springboot项目生成时的默认配置文件优先级是最低的
image-20200920122317741

  • 优先级由高到底,高优先级的配置会覆盖低优先级的配置;
  • SpringBoot会从这四个位置全部加载主配置文件;互补配置;

我们在最低级的两个配置文件中设置项目访问路径和端口号的配置来测试互补问题

在默认位置(第四加载位置)的propertiesyaml两个配置文件中添加以下代码测试

#配置项目的访问路径
server.servlet.context-path=/zsr
server:
  servlet:
    context-path: /zzz #配置项目的访问路径
  port: 8081 #配置端口号

然后启动项目测试,可以看到,最终配置的项目访问路径是/zsr ,且访问端口为8081
image-20201008200955906
因此:当两个配置文件同时存在的时候,相同的配置会优先加载properties 配置文件,多余的配置的会互补配置;

4. 多环境切换

实际开发中,我们针对不同的应用场景,可能有不同的环境,不同的配置文件

profile就是Spring对不同环境提供不同配置功能的支持,可以通过激活不同的环境版本,实现快速切换环境,

方式一:多配置文件

我们再编写配置文件时,文件名可以是application-{profile}.properties/yml,用来指定多个不同的环境版本;

例如(properties格式)

application.properties 代表主环境

# /src/main/resources/application.properties
server.port=8080

application-test.properties 代表测试环境配置

# /src/main/resources/application-test.properties
server.port=8081

application-dev.properties 代表开发环境配置

# /src/main/resources/application-dev.properties
server.port=8082

当我们运行测试时,如果未加指定,它默认使用application.properties主配置文件;

实际开发中,面对不同的环境,我们可以在默认配置文件application,properties中指定所需的配置文件环境,例如以下指定使用dev的配置文件:

# /src/main/resources/application.properties
server.port=8080
spring.profiles.active=dev

此后再启动SpringBoot,就可以看到已经切换到dev下的配置环境;

YAML格式亦是如此

image-20200920125248798

方式二:一个配置文件(yaml的多文档块)

yaml多文档块:可以在一个配置文件中配置多个环境并根据需要进行选择,无需上述多个配置文件,更为方便

server:  
	port: 8080
#选择要激活那个环境块
spring:  
	profiles:    
		active: prod
		
---
server:  
	port: 8081
spring:  
	profiles: dev #配置环境名称dev

---
server:  
	port: 8082
spring:  
	profiles: prod  #配置环境名称prod

注意:如果yml和 properties的配置文件同时存在,同时都配置了端口,但是yaml多环境没有指定环境,默认会使用properties配置文件的!


二、YAML配置注入

当我们新建一个项目Springboot项目时,默认使用properties格式的配置文件,其实SpringBoot还支持yaml格式的配置文件,且这是最流行,最为广泛使用的

1. YAML入门

1、什么是YAML?

YAML 有两种展开方式:

  • YAML Ain't a Markup Language:YAML 不是一种标记语言
  • Yet Another Markup Language:YAML是一种标记语言

之所以用反向缩略语重命名,是为了强调 YAML以数据做为中心,而不是以标记语言为重点

功能

  • YAML的语法和其他高级语言类似,并且可以简单表达清单、散列表,标量等数据形态。
  • 它使用空白符号缩进和大量依赖外观的特色,特别适合用来表达或编辑数据结构、各种配置文件、倾印调试内容、文件大纲(例如:许多电子邮件标题格式和YAML非常接近)

2、对比传统标记语言

以前的配置文件,大多数都是使用 XML 来配置;YAML 作为一种比 XML 更为简单易读的序列化语言,正越来越多地被用于应用及配置文件的开发中

比如一个简单的端口配置,我们来对比下yaml和xml:

<!--传统xml配置-->
<server>
    <port>8081<port>
</server>
#YAML配置
server:
  prot: 8080

简单的一个对比就可以看出:YAML可读性好,易于实现

不仅如此,YAML还有很多其他有点:

  • YAML和脚本语言的交互性好
  • YAML使用实现语言的数据类型
  • YAML有一个一致的信息模型
  • YAML可以基于流来处理
  • YAML表达能力强,扩展性好

总之,YAML试图用一种比XML更敏捷的方式,来完成XML所完成的任务

3、基本语法

  • 大小写敏感
  • 使用缩进表示层级关系
  • 缩进不允许使用tab,只允许空格
  • 缩进的空格数不重要,只要相同层级的元素左对齐即可
  • #表示注释

4、数据类型

YAML 支持以下几种数据类型:

  • 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
  • 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
  • 纯量(scalars):单个的、不可再分的值
对象

对象键值对使用冒号结构表示 key: value,冒号后面要加一个空格。

password: 123456

对象的行内写法:

User: {name: zsr,age: 20}

还可以使用缩进表示层级关系:

User:
  name: zsr
  age: 20
数组

- 值表示数组中的一个元素,比如:

pets:
 - cat
 - dog
 - pig

行内写法

pets: [cat,dog,pig]

数据结构的子成员是一个数组,则可以在该项下面缩进一个空格,例如:

companies:
    -
        id: 1
        name: company1
        price: 200W
    -
        id: 2
        name: company2
        price: 500W

意思是 companies 属性是一个数组,每一个数组元素又是由 id、name、price 三个属性构成。

数组也可以使用流式(flow)的方式表示:

companies: [{id: 1,name: company1,price: 200W},{id: 2,name: company2,price: 500W}]
纯量

纯量是最基本的,不可再分的值,包括:

  • 字符串
  • 布尔值
  • 整数
  • 浮点数
  • Null
  • 时间
  • 日期

纯量直接写在后面就可以,字符串默认不用加上双引号或者单引号;

key: value

当写一些特殊字符时,我们可能会用上单引号或者双引号:

  • " " 双引号:不会转义字符串里面的特殊字符 , 特殊字符会作为本身想表示的意思;
#比如
name: "kuang \n shen"  
#输出 
kuang 换行 shen
  • ' ' 单引号:会转义特殊字符 , 特殊字符最终会变成和普通字符一样输出
#比如
name: ‘kuang \n shen’  
#输出
kuang \n shen

使用一个例子来快速了解纯量的基本使用:

boolean: 
    - TRUE  #true,True都可以
    - FALSE  #false,False都可以
float:
    - 3.14
    - 6.8523015e+5  #可以使用科学计数法
int:
    - 123
    - 0b1010_0111_0100_1010_1110    #二进制表示
null:
    nodeName: 'node'
    parent: ~  #使用~表示null
string:
    - 哈哈
    - 'Hello world'  #可以使用双引号或者单引号包裹特殊字符
    - newline
      newline2    #字符串可以拆成多行,每一行会被转化成一个空格
date:
    - 2018-02-17    #日期必须使用ISO 8601格式,即yyyy-MM-dd
datetime: 
    -  2018-02-17T15:02:31+08:00    #时间使用ISO 8601格式,时和日期之间使用T连接,最后使用+代表时区

2. SpringBoot——yaml注入配置文件

yaml文件更强大的地方在于,他可以给我们的实体类直接注入匹配值!

1、编写一个实体类 Dog

在主程序同级目录下新建pojo包,在包下新建一个Dog实体类

image-20200920110431397

package com.zsr.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;

@Data
@AllArgsConstructor//有参构造
@NoArgsConstructor//无参构造
@Component//注册bean到容器中
public class Dog {
    private String name;
    private Integer age;
}

2、编写一个Person实体类

Person类,包含所有常见数据类型,以及Dog对象

@Data
@AllArgsConstructor
@NoArgsConstructor
@Component //注册bean到容器中
public class Person {
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String, Object> maps;
    private List<Object> lists;
    private Dog dog;
}

3、编写yaml配置文件

在springboot项目中的resources目录下新建一个文件 application.yml,使用yaml配置的方式进行注入

image-20200920110327482

person:
  name: zsr
  age: 20
  happy: True
  birth: 2000/02/04
  maps: {k1: v1,k2: v2}
  lists:
    - guitar
    - sing
    - play
  dog:
    name: 多多
    age: 4

4、yaml配置注入

刚才已经把person对象的所有属性值都写好了

再通过@ConfigurationProperties注解注入到我们的类中,

/*
@ConfigurationProperties作用:
	将配置文件中配置的每一个属性的值,映射到这个组件中;
	告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定
	参数 prefix = “person” : 将配置文件中的person下面的所有属性一一对应
*/
@Component //注册bean
@ConfigurationProperties(prefix = "person")
public class Person {
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;
}

IDEA爆红提示:springboot配置注解处理器没有找到,我们点击Open Document查看文档
image-20200919110130064
image-20200919110736754
发现未找到,我们降低版本为2.1.9即可

https://docs.spring.io/spring-boot/docs/2.1.9.RELEASE/reference/html/configuration-metadata.html#configuration-metadata-annotation-processor

进入到网页中,可以找到一个依赖,加上他,就不会爆红提示
image-20200919115857791

<!-- 导入配置文件处理器-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-configuration-processor</artifactId>
	<optional>true</optional>
</dependency>

5、测试

配置完成后,我们修改测试类进行测试

package com.zsr;

import com.zsr.pojo.Dog;
import com.zsr.pojo.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class Springboot02ConfigApplicationTests {
    @Autowired //将person自动注入进来
    private Person person;

    @Test
    void contextLoads() {
        System.out.println(person); //打印看下person对象
    }
}

结果:所有值全部注入成功!yaml配置成功注入到实体类!
image-20200919120937486

6、加载指定的配置文件

以上我们通过@configurationProperties注解默认从全局配置文件中获取值

  • 此时配置文件名必须为application才能被spring认出
  • 其实我们可以通过@PropertySource指定加载的配置文件,可以自定义文件名

1、我们去在resources目录下新建一个person.properties文件

name=zsr
age=20
happy=True
birth=2000/02/04
lists=guitar,sing,play

2、相应修改对应的实体类,用@PropertySource注解加载指定person.properties文件

package com.zsr.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

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

@Data
@AllArgsConstructor
@NoArgsConstructor
@Component //注册bean到容器中
@PropertySource(value = "classpath:person.properties")
public class Person {
    //SPEL表达式取出指定的值
    @Value("${name}")
    private String name;
    @Value("${age}")
    private Integer age;
    @Value("${happy}")
    private Boolean happy;
    @Value("${birth}")
    private Date birth;
    private Map<String, Object> maps;
    @Value("${lists}")
    private List<Object> lists;
    //properties不能存对象
    private Dog dog;
}

3、修改测试类

package com.zsr;

import com.zsr.pojo.Dog;
import com.zsr.pojo.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class Springboot02ConfigApplicationTests {
    @Autowired //将person自动注入进来
    private Person person;
    @Test
    void contextLoads() {
        System.out.println(person); //打印看下person对象
    }
}

4、运行测试

指定配置文件绑定成功!
image-20200919140057495

7、yaml配置文件占位符

yaml配置文件还可以编写占位符生成随机数

person:
    name: zsr${random.uuid} # 随机uuid
    age: ${random.int}  # 随机int
    happy: true
    birth: 2000/02/04
    maps: {k1: v1,k2: v2}
    lists:
      - guitar
      - sing
      - play
    dog:
      name: ${person.hello:other}_多多
      age: 4

然后运行测试:
image-20200920112656038

3. 对比回顾properties配置

以上采用的yaml配置文件是最简单且最常用的方式;也是springboot所推荐的!

接下来来对比一下默认的properties配置文件

:properties配置文件在写中文的时候,会有乱码,我们需要去IDEA中设置编码格式为UTF-8;
image-20200919173846087

测试properties配置文件

1、新建一个实体类User

package com.zsr.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;
    private int age;
    private String sex;
}

2、编辑配置文件 user.properties

name=zsr

3、我们在User类上使用@Value来进行注入!

package com.zsr.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Value;

@Component
@Data
@AllArgsConstructor
@NoArgsConstructor
@PropertySource(value = "classpath:user.properties")
public class User {
    //直接使用@value()
    @Value("${user.name}")//从配置文件中取值
    private String name;
    @Value("#{9*2}")//SPEL表达式:@Value("#{表达式}")
    private int age;
    @Value("男") //纯量
    private String sex;
}

4、Springboot测试类测试

package com.zsr;

import com.zsr.pojo.Person;
import com.zsr.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class Springboot02ConfigApplicationTests {

    @Autowired //将user自动注入进来
    private User user;

    @Test
    void contextLoads() {
        System.out.println(user); //打印看下person对象
    }

}

结果正常输出:
image-20200920120742665

对比小结

image-20200920121117587

  1. @ConfigurationProperties只需要写一次即可,@Value则需要对每个字段都添加
  2. 松散绑定:比如我的yaml中写的 last-name,这个和 lastName 是一样的,- 后面跟着的字母默认是大写的,这就是松散绑定
  3. JSR303数据校验:可以在字段是增加一层过滤器验证,可以保证数据的合法性
  4. 复杂类型封装:yaml中可以封装对象,使用@value就不支持

最佳实践

  • 配置 yaml 和配置 properties 都可以获取到值时,首荐 yaml;
  • 如果在某个业务中,只需要获取配置文件中的某个值,可以使用一下@value
  • 如果有编写的JavaBean来和配置文件进行一一映射,就直接@configurationProperties

原文:SpringBoot配置文件&YAML配置注入(详解)_spring的yml注入-CSDN博客
作者: Baret-H