SpringBoot从入门到精通—配置文件详解

1、Spring Boot配置文件

    Spring Boot支持两种形式的配置文件,分别是.properties、和.yml,而且配置文件的名字是固定不可变的: * application.properties * application.yml

    配置文件的作用是修改Spring Boot自动配置的默认值。相对于properties文件而言,yml文件更年轻,也有很多的坑。下面我们就来一一学习一下。     注意:当application.properties文件和application.yml同时存在的时候,application.properties会优先加载,application.yml则后加载,而且在applicatin.properties中已经加载的属性如果在application.yml中再次出现会被忽略,如果是application.yml中的独有的属性则会加载。

2、YAML/YML文件简介

2.1 什么是YAML/YML文件

    YAML是"YAML Ain't a Markup Language"(YAML不是一种置标语言)的递回缩写。YAML 是一个可读性高,用来表达资料序列的编程语言。YAML是一种直观的能够被电脑识别的的数据数据序列化格式,容易被人类阅读,容易和脚本语言交互的,可以被支持YAML库的不同的编程语言程序导入,比如: C/C++, Ruby, Python, Java, Perl, C#, PHP等。YAML以数据为中心,比json、xml等更适合做配置文件

2.2 YAML/YML的基本语法

基本语法key: value,key: 和value中间要有一个空格,而且key: value的形式可以写无限层。还有一下规则: 1.大小写敏感 2.使用缩进表示层级关系 3.缩进时不允许使用Tab键,只允许使用空格。 4.缩进的空格数目不重要,只要相同层级的元素左侧对齐即可 5.只有一种注释方式,使用#

2.3 YAML/YML支持的数据结构

YML支持3中类型的数据结构类型

1.字面量 2.对象(属性和值),Map(键值对) 3.数组(List、Set)

1、字面量具体包括:字符串、布尔值、整数、浮点数、Null、时间、日期 字面量可以直接使用,但是特别注意字符串的字面量在写的时候是不需要引号的(无论单引号还是双引号)。单/双引号在yml语法中有特殊的含义:​ * “”:双引号;会转义字符串里面的特殊字符;特殊字符会作为本身想表示的意思 ​ name: “zhangsan \n lisi”:输出;zhangsan 换行 lisi * ​ ”:单引号;不会转义特殊字符,特殊字符最终只是一个普通的字符串数据 name: ‘zhangsan \n lisi’:输出;zhangsan \n lisi

2.对象(属性和值),Map(键值对) 基本的语法还是key:value,以一个例子来说明:

friends:
		lastName: zhangsan
		age: 20

对应的行内写法:

friends: {lastName: zhangsan,age: 18}

3.数组(List、Set) 用- 值表示数组中的一个元素

pets:
  - cat
  - dog
  - pig

行内写法

pets: [cat,dog,pig]

举个栗子:配置一个Person的信息

package com.xust.iot.bean;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

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


/**
 * @ConfigurationProperties:告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定;
 * 但是要特别注意:只有这个组件是容器中的组件,容器才能提供@ConfigurationProperties的功能;
 */
@Component
@ConfigurationProperties(prefix="person")
public class Person {

    private String name;
    private Integer age;
    private Address address;
    private Map<String,Object> map;
    private List<String> list;

   //省略getter setter和toStrig方法

package com.xust.iot.bean;

public class Address {


    private String province;
    private String city;
    private String county;
    private String street;

  //省略getter setter和toStrig方法
}

我们可以导入配置文件处理器,编写配置的时候就有提示了

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

在application.yml配置文件中配置preson信息:

#写yml配置的时候要特别注意key和value之间要有一个空格,同级属性左对齐
person:
  name: 李四
  age: 20
  map:
    key1: value1
    key2: value2
  list:
    - hello
    - hi
    - bye
  address:
    province: 陕西
    city: 西安
    county: xx
    street: xx

在SpringBoot测试类中测试IOC是否可以拿到在配置文件中配置的信息

package com.xust.iot;

import com.xust.iot.bean.Person;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootConfigApplicationTests {


    @Autowired
    Person person;

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

测试结果:

3、properties文件简介

    properties文件大家经常用,这里就简单介绍一下。其语法结构形如:key=value。注意中文乱码问题,需要转码成ASCII。在IDEA中可以设置自动转换把uft-8格式自动转成ASCII,设置方式是:依次点击【File】=>【Other Settings】=>【settigs for new projects】,搜索File Encodings,然后做如下配置:

上面Person信息的properties配置如下:

person.name=小明
person.age=20
person.address.province=陕西
person.address.city=西安
person.address.county=xx
person.address.street=xx
person.map.key1=value1
person.map.key2=value2
person.list=hello,hi,bye

4、配置文件值注入

4.1 @Value获取值和@ConfigurationProperties获取值比较

    Spring Boot通过ConfigurationProperties注解从配置文件中获取属性。从上面的例子可以看出ConfigurationProperties注解可以通过设置prefix指定需要批量导入的数据。支持获取字面值,集合,Map,对象等复杂数据。ConfigurationProperties注解还有其他特么呢?它和Spring的Value注解又有什么区别呢?带着这些问题,我们继续往下看。

比较@ConfigurationProperties @Value
功能 批量注入配置文件中的属性 一个个指定
松散绑定(松散语法) 支持 不支持
SpEL 不支持 支持
JSR303数据校验 支持 不支持
复杂类型封装 支持 不支持
**何时使用@Value何时使用@ConfigrationProperties?** 如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用@Value。

如果说,我们专门编写了一个javaBean来和配置文件进行映射,我们就直接使用@ConfigurationProperties。

4.1 配置文件注入值数据校验

使用@Vaildatad可以给配置的属性数据校验功能。可以用在类、方法、参数上。可以加的验证注解如下:

@Null	//限制只能为null
@NotNull	//限制必须不为null
@AssertFalse	//限制必须为false
@AssertTrue	   //限制必须为true
@DecimalMax(value)	//限制必须为一个不大于指定值的数字
@DecimalMin(value)	//限制必须为一个不小于指定值的数字
@Digits(integer,fraction)	//限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@Future	//限制必须是一个将来的日期
@Max(value)	//限制必须为一个不大于指定值的数字
@Min(value)	//限制必须为一个不小于指定值的数字
@Past	//验证注解的元素值(日期类型)比当前时间早
@Pattern(value)	//限制必须符合指定的正则表达式
@Size(max,min)	//限制字符长度必须在min到max之间
@NotEmpty	//验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@NotBlank	//验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank   //只应用于字符串且在比较时会去除字符串的空格
@Email	//验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式

下面举个例子:

@Component
@ConfigurationProperties(prefix = "person")
@Validated
public class Person {


    @NotEmpty
    @Size(max = 5, min = 2)
    private String name;
    
    @Max(70)
    @Min(10)
    private Integer age;

    @Past
    private Date birth;

    @NotEmpty
    private Address address;
    
    @NotEmpty
    private Map<String, Object> map;
    
    @NotEmpty
    private List<String> list;

 //省略getter setter和toStrig方法
  
 }
4.2 @PropertySource&@ImportResource&@Bean
  • @PropertySource:加载指定的配置文件;

person.properties

person.name=小明
person.age=20
person.address.province=陕西
person.address.city=西安
person.address.county=xx
person.address.street=xx
person.map.key1=value1
person.map.key2=value2
person.list=hello,hi,bye
person.birth=2019/04/5
package com.xust.iot.bean;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.*;
import java.util.Date;
import java.util.List;
import java.util.Map;


//使用PropertySource注解指定配置文件的路径,SpringBoot就会在启动的时候加载,然后把配置中的值赋给这个配置类的对应属性。
@PropertySource(value = {"classpath:personInfo.properties"})
@Component
@ConfigurationProperties(prefix = "person")
@Validated
public class Person {


    @NotEmpty
    @Size(max = 5, min = 2)
    private String name;

    @Max(70)
    @Min(10)
    private Integer age;

    @Past
    private Date birth;

    private Address address;

    @NotEmpty
    private Map<String, Object> map;

    @NotEmpty
    private List<String> list;

 //省略getter setter和toStrig方法
}
  • @ImportResource:导入Spring的配置文件,让配置文件里面的内容生效;

在src/main/resources下新建一个Spring配置文件applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="address" class="com.xust.iot.bean.Address">
        <property name="province" value="陕西"/>
        <property name="city" value="汉中"/>
        <property name="county" value="xxx"/>
        <property name="street" value="xxx"/>
    </bean>
</beans>

在Spring Boot的主程序类中使用@ImportResource引入配置这个配置文件

然后在测试类中自动注入ApplicationContext来拿这个组件

package com.xust.iot;

import com.xust.iot.bean.Person;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootConfigApplicationTests {

    @Autowired
    ApplicationContext ioc;

    @Test
    public void contextLoads() {

       System.out.println(ioc.containsBean("address"));

       System.out.println(ioc.getBean("address").toString());

    }
}

测试结果:

虽然这种方式可以用,但是一般我们不这么用,而且Spring Boot也不推荐这么使用,Spring Boot推荐使用全注解的方式来添加配置文件。 * 1、配置类**@Configuration**------>Spring配置文件

  • 2、使用**@Bean**给容器中添加组件

接下类,我们在com.xust.iot基包下新建配置类ApplicationConfig.java

package com.xust.iot;

import com.xust.iot.bean.Address;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//使用@Configuration告诉Spring这是配置
@Configuration
public class ApplicationConfig {


    //@Bean注解相当于<bean></bean>标签,特别注意:方法名就是bean的id
    @Bean
    public Address address(){
        System.out.println("在配置类中使用@Bean注解添加了组件");
        Address address=new Address();
        address.setProvince("陕西省");
        address.setCity("西安");
        address.setCounty("xxx");
        address.setStreet("xxx");

        return address;
    }
}

运行后得到的效果一样:

5、配置文件占位符

在application.properties和application.yml文件可以使用${random}来设置随机值

5.1 常用随机设值如下
${random.value}    //随机生成一个32位的字符串,如:b21d56d2f10d74f84608dfff01b25552
${random.int}    //随机生成一个int范围的随机数
${random.long}   //随机生成一个int范围的随机数
${random.int(10)}  //随机生一个[0,10]之间的随机数
${random.int[1024,65536]}   //随机生成一个[1024,65536]之间的随机数
${对象.属性}   //使用某个已配置的属性的值
${对象.属性:默认值}   //使用某个已配置的属性的值,如果没有就是用默认值

在application.yml文件中写如下配置:

person:
  name: 李四${random.uuid}
  age: ${random.int(45,70)}
  birth: 2019/08/24
  map:
    key1: 232424@qq.com
    key2: dad323@163.com
  list:
    - hello
    - hi
    - bye
  address:
    province: 陕西
    city: 西安
    county: ${person.name}
    street: ${person.address.province}-${person.address.city}

在测试类中打印person的信息,结果如下:

6、Spring Boot profile

    Spring支持对不同环境,提供不同配置,可以通过激活、指定参数等方式快速的切换环境 。环境profile可以是开发环境(develop)、测试环境(fuy)、生产环境(production)等

6.1 配置多个profile

在主配置文件编写的时候,文件名可以是 application-{profile_name}.properties/yml,比如下面分别编写的application-develop.properties和application-production.properties

application-develop.properties

debug=true
server.port=8081
server.servlet.acontext-path=/book

application-production.properties

debug=false
server.port=80
server.servlet.context-path=/book

目录结构:

在主配置文件application.properties中,使用spring.profiles.active=[profile]来激活不同的环境,如下激活develop环境:

启动Spring Boot观察Tomcat启动的端口

激活生产环境:spring.profiles.active=production

可以看到,配置的不同环境被激活后都起作用了。这在以后的开发中无疑是个十分强大而且方便的功能。
6.2 YML配置多个profile

然而使用properties文件配置不同环境还是太麻烦了,YML对多profile的支持更加简单粗暴,直接通过连续的三个-就可以划分出不同的文件,配置示例:

#主配置文件
server:
  port: 8083
spring:
   profiles:
     active: production  #激活生产环境
---
#开发环境
server:
  port: 8083
  servlet:
    context-path: /boot
debug: true
spring:
  profiles: develop   #使用spring.profiles来指定这个环境名

---   #使用连续的三个横线分隔不同的profile(文档区)
#生产环境
server:
  port: 80
  servlet:
    context-path: /boot
debug: true
spring:
  profiles: production

注意:Spring Boot启动的时候会优先加载.properties的文件,然后才来加载.yml文件,如果要想使applicaton.yml中配置的信息可以使用,那么.properties中不能有和.yml相同的配置。

6.3 激活指定profile的不同方式

1、在主配置文件中指定 spring.profiles.active=dev,上面的配置方式就是这种。

2、命令行: 可以在IDEA中配置 --spring.profiles.active=develop 来启动开发环境,操作如下:

也可以在命令行中使用java -jar spring_boot_config-0.0.1-SNAPSHOT.jar --spring.profiles.active=develop来启动开发环境
3、虚拟机参数: 可以在IDEA中做如下配置:-Dspring.profiles.active=dev,示例如下:

7、配置文件的加载位置

springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件

–file:./config/

–file:./

–classpath:/config/

–classpath:/

这些位置的配置文件加载的优先级由高到底,而且高优先级的配置如果在低优先即中出现,那么低优先优先级中重复配置不会生效。但是低优先级中独有的配置还是会生效。也就是说SpringBoot会从这四个位置全部加载主配置文件;并且会互补配置

==我们还可以通过spring.config.location来改变默认的配置文件位置==

比如:项目打包好以后,我们可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置;指定配置文件和默认加载的这些配置文件共同起作用形成互补配置; 首先在硬盘的另一个地方(我这里在E://)创建application.properties。添加如下配置:

debug=false
server.port=8087
server.servlet.context-path=/book
然后可以在命令行输入java -jar spring_boot_config-0.0.1-SNAPSHOT.jar --spring.config.location=E://application.properties
#### 8、外部配置加载顺序 **==SpringBoot也可以从以下位置加载配置,加载顺序的优先级从高到低;高优先级的配置会覆盖低优先级的配置,所有的配置会形成互补配置==**。 **1.命令行参数** 所有的配置都可以在命令行上进行指定 java -jar spring_boot_config-0.0.1-SNAPSHOT.jar --server.port=8087 --server.context-path=/abc 多个配置用空格分开;` --配置项=值` 2.来自java:comp/env的JNDI属性 3.Java系统属性(System.getProperties()) 4.操作系统环境变量 5.RandomValuePropertySource配置的random.*属性值 ==**由jar包外向jar包内进行寻找;**== ==**优先加载带profile的配置文件**== **6.jar包外部的application-{profile}.properties或application.yml(带spring.profile)配置文件** **7.jar包内部的application-{profile}.properties或application.yml(带spring.profile)配置文件** ==**再来加载不带profile的配置文件**== **8.jar包外部的application.properties或application.yml(不带spring.profile)配置文件** **9.jar包内部的application.properties或application.yml(不带spring.profile)配置文件** 10.@Configuration注解类上的@PropertySource 11.通过SpringApplication.setDefaultProperties指定的默认属性 所有支持的配置加载来源[参考官方文档](https://docs.spring.io/spring-boot/docs/1.5.9.RELEASE/reference/htmlsingle/#boot-features-external-config)。

留言区

还能输入500个字符