前言

配置文件一般存放一些系统变量或用户变量,例如数据库数据源的配置。它可以实现在不改变程序源代码的情况下修改程序的变量的值。通过配置文件可以使程序开发变得更加灵活。接下来我将介绍几种常见的在 SpringBoot 中获取配置文件的方式。

我的示例配置文件(userinfo.yml)位置如下:

image-20220930203751776

1
2
3
4
5
6
7
8
9
10
11
12
my-profile:
name: grape
age: 6


users:
- name: 张三
age: 20
- name: 李四
age: 21
- name: 王五
age: 22

通过 @value 读取简单信息

通过在变量前加上注解 @value("${xxx}") 可以将配置信息注入到变量中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.pushihao.controller;

import com.pushihao.bean.YmlConfigFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@PropertySource(value = {"classpath:userinfo.yml"},encoding="UTF-8",factory = YmlConfigFactory.class)
public class UserinfoController {
@Value("${my-profile.name}")
private String name;

@Value("${my-profile.age}")
private String age;


@RequestMapping("/u1")
public String u1() {
return "name:" + name + "|age:" + age;
}
}

注意:

@PropertySource 注解可以指定要读取的配置文件的位置。不写此注解默认读取SpringBoot默认配置文件application.properties/application.yml/application.yaml。

因为 @PropertySource 注解默认是读取 properties 文件,所以如果是读取 properties 文件,注解可以写成 @PropertySource(value = {“classpath:userinfo.properties”},encoding=”UTF-8”)。

本例中读取的是 yml 文件,需要重写 DefaultPropertySourceFactory,让其加载 yml 文件。然后在 PropertySource 注解中加入factory = YmlConfigFactory.class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.pushihao.bean;

import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.DefaultPropertySourceFactory;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Properties;

@Component
public class YmlConfigFactory extends DefaultPropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException, IOException {
String sourceName = name != null ? name : resource.getResource().getFilename();
if (!resource.getResource().exists()) {
assert sourceName != null;
return new PropertiesPropertySource(sourceName, new Properties());
} else {
assert sourceName != null;
if (sourceName.endsWith(".yml") || sourceName.endsWith(".yaml")) {
Properties propertiesFromYaml = loadYml(resource);
return new PropertiesPropertySource(sourceName, propertiesFromYaml);
} else {
return super.createPropertySource(name, resource);
}
}
}

private Properties loadYml(EncodedResource resource) throws IOException {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(resource.getResource());
factory.afterPropertiesSet();
return factory.getObject();
}
}

通过 Environment 读取配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.pushihao.controller;

import com.pushihao.bean.YmlConfigFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@PropertySource(value = {"classpath:userinfo.yml"},encoding="UTF-8",factory = YmlConfigFactory.class)
public class Userinfo2Controller {

@Autowired
private Environment environment;

@RequestMapping("/u2")
public String u2() {
String name = environment.getProperty("my-profile.name");
String age = environment.getProperty("my-profile.age");
return "name:" + name + "|age:" + age;
}
}

通过 @ConfigurationProperties 读取配置文件

@ConfigurationProperties 注解可以将配置文件映射成一个类,而配置文件中的每个键就对应类中的每个属性

映射类代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.pushihao.bean;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
@Data
@PropertySource(value = {"classpath:userinfo.yml"},encoding="UTF-8",factory = YmlConfigFactory.class)
//注意:prefix指定的是键的前缀,而不是文件名的前缀
@ConfigurationProperties(prefix = "")
public class UserinfoProperties {

//注意:此处的变量名称要和配置文件中的键的名称相对应,采用驼峰命名法
private User myProfile = new User();

private List<User> users = new ArrayList<>();


@Data
public static class User {
String name;

Integer age;
}
}

使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.pushihao.controller;

import com.pushihao.bean.UserinfoProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Userinfo3Controller {
@Autowired
private UserinfoProperties userinfoProperties;

@RequestMapping("/u3")
public String u3() {
return "name:" + userinfoProperties.getMyProfile().getName()
+ "|age:" + userinfoProperties.getMyProfile().getAge()
+ "|users:" + userinfoProperties.getUsers().toString();
}
}

其他

配置文件优先级

位置决定优先级:

Config data files are considered in the following order:

  1. Application properties packaged inside your jar ( and YAML variants).application.properties
  2. Profile-specific application properties packaged inside your jar ( and YAML variants).application-{profile}.properties
  3. Application properties outside of your packaged jar ( and YAML variants).application.properties
  4. Profile-specific application properties outside of your packaged jar ( and YAML variants).application-{profile}.properties

文件后缀名决定优先级:

yml 读取优先级 > properties 读取优先级