SpringBoot_配置
2025-01-22 08:19:30    2.9k 字   
This post is also available in English and alternative languages.

Spring Framework版本:5.1.6.RELEASE (点击跳转官方文档)
SpringBoot版本:2.1.4.RELEASE (点击跳转官方文档)

SpringBoot Configuration.


1. 多环境配置

不同的环境配置不同的参数,而且便于部署,减少出错;配置文件的命名规则遵循 application-${profile}.properties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# application.yml
spring:
profiles:
active: dev
# active: prod
application:
name: springboot-example-01
server:
port: 9401
servlet:
context-path: /api

# application-dev.yml
star:
url: www.google.com
address: 南京

# application-prod.yml
star:
url: www.baidu.com
address: 北京
  • application.yml:默认配置文件。
  • application-dev.yml:dev 环境的配置文件。
  • application-prod.yml:prod 环境的配置文件。

application.yml 配置文件中,通过设置 spring.profiles.active 来切换选择读取哪个配置文件。

相关测试代码:

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
@Data
@Configuration
@ConfigurationProperties(prefix = "star")
public class StarConfigProperty {
private String url;
private String address;
}

@Slf4j
@SpringBootApplication
public class ApplicationSpringBootExample01 {

@Resource
StarConfigProperty starConfigProperty;

public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(ApplicationSpringBootExample01.class, args);
ApplicationSpringBootExample01 applicationContextBean = applicationContext.getBean(ApplicationSpringBootExample01.class);
applicationContextBean.process();
}

private void process() {
log.info("===== starConfigProperty:{}", starConfigProperty);
}
}

2. 配置文件细分

上面基于环境,对配置文件进行了区分,dev 环境和 prod 环境的配置内容是不同的;

基于环境,现在继续对配置文件进行拆分,数据库单独一个配置文件,redis单独一个配置文件。配置文件的命名规则遵循 application-${profile}.properties

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# application.yml
spring:
profiles:
active: dev
include: devRedis,devDatabase
# active: prod
# include: prodRedis,prodDatabase
application:
name: springboot-example-01

server:
port: 9401
servlet:
context-path: /api

# application-dev.yml
star:
url: www.google.com
address: 南京

# application-prod.yml
star:
url: www.baidu.com
address: 北京

# application-devRedis.yml
example:
redis:
database: 1
host: 127.0.0.1
port: 6379
timeout: 5000

# application-devDatabase.yml
example:
database:
url: jdbc:mysql://localhost/xxxx?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
passwrod: 123456

# application-prodRedis.yml
example:
redis:
database: 2
host: 127.0.0.2
port: 63792
timeout: 50002

# application-prodDatabase.yml
example:
database:
url: 2jdbc:mysql://localhost/xxxx?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: 2root11
passwrod: 212345611
  • application.yml:默认配置文件。
  • application-dev.yml:dev 环境的配置文件。
  • application-devRedis.yml:dev 环境的 redis 配置。
  • application-devDatabase.yml:dev 环境的数据配置
  • application-prod.yml:prod 环境的配置文件。
  • application-prodRedis:prod 环境的 redis 配置。
  • application-prodDatabase:prod 环境的数据库配置。

application.yml 配置文件中,通过设置spring.profiles.include来关联各个细分的配置文件。

相关测试代码:

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
39
40
41
42
43
44
45
46
47
48
49
@Data
@Configuration
@ConfigurationProperties(prefix = "example.database")
public class DataSourceProperty {
private String url;
private String username;
private String passwrod;
}

@Data
@Configuration
@ConfigurationProperties(prefix = "example.redis")
public class RedisProperty {
private Integer database;
private String host;
private Integer port;
private Long timeout;
}

@Data
@Configuration
@ConfigurationProperties(prefix = "star")
public class StarConfigProperty {
private String url;
private String address;
}

@Slf4j
@SpringBootApplication
public class ApplicationSpringBootExample01 {
@Resource
StarConfigProperty starConfigProperty;
@Resource
DataSourceProperty dataSourceProperty;
@Resource
RedisProperty redisProperty;

public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(ApplicationSpringBootExample01.class, args);
ApplicationSpringBootExample01 applicationContextBean = applicationContext.getBean(ApplicationSpringBootExample01.class);
applicationContextBean.process();
}

private void process() {
log.info("starConfigProperty:[{}]", starConfigProperty);
log.info("dataSourceProperty:[{}]", dataSourceProperty);
log.info("redisProperty:[{}]", redisProperty);
}
}

3. ConfigurationProperties注解

以下示例,使用 @Configuration 注解实例化 Bean,同时修饰 Bean 为配置类。搭配使用 @ConfigurationProperties 注解使用配置文件中前缀为 star 的值,初始化该 Bean 中同名的属性。

当 Bean 被实例化时,@ConfigurationProperties 会将对应前缀的后面的属性与 Bean 对象的属性匹配,对符合条件则进行赋值。
如果只配置 @ConfigurationProperties 注解不配置 @Configuration 注解,在IOC容器中是获取不到配置文件转化后的 Bean 的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# application.yml
spring:
profiles:
active: dev
application:
name: springboot-example-01
server:
port: 9401
servlet:
context-path: /api

# application-dev.yml
star:
url: www.google.com
address: 南京

# application-prod.yml
star:
url: www.baidu.com
address: 北京

3.1. 作用于方法上

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
@Data
public class StarConfigProperty {
private String url;
private String address;
}

@Configuration
public class Model02Config {
@ConfigurationProperties(prefix = "star")
@Bean(name = "starConfigProperty")
public StarConfigProperty createStarConfigProperty() {
return new StarConfigProperty();
}
}

@Slf4j
@SpringBootApplication
public class ApplicationSpringBootExample01 {

@Resource
StarConfigProperty starConfigProperty;

public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(ApplicationSpringBootExample01.class, args);
ApplicationSpringBootExample01 applicationContextBean = applicationContext.getBean(ApplicationSpringBootExample01.class);
applicationContextBean.process();
}

private void process() {
log.info("===== :{}", starConfigProperty);
}
}

3.2. 作用于类上

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
@Data
@Configuration
@ConfigurationProperties(prefix = "star")
public class StarConfigProperty {
private String url;
private String address;
}

@Slf4j
@SpringBootApplication
public class ApplicationSpringBootExample01 {

@Resource
StarConfigProperty starConfigProperty;

public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(ApplicationSpringBootExample01.class, args);
ApplicationSpringBootExample01 applicationContextBean = applicationContext.getBean(ApplicationSpringBootExample01.class);
applicationContextBean.process();
}

private void process() {
log.info("===== starConfigProperty:{}", starConfigProperty);
}
}

3.3. 激活ConfigurationProperties注解

可以使用 @Configuration@Component 注解,让 Component Scan 扫描到并加载到 IOC 中,例如 作用于方法上作用于类上 两个小节中代码示例,也可以使用 @EnableConfigurationProperties 注解,单独添加到 IOC 容器中。


3.3.1. EnableConfigurationProperties注解

通过配置 @EnableConfigurationProperties 注解,将配置类加载到 IOC 容器中。如果只配置 @ConfigurationProperties 注解,不配置 @EnableConfigurationProperties 注解,在IOC容器中是获取不到配置文件转化的 Bean 的。

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
@Data
@ConfigurationProperties(prefix = "star")
public class StarConfigProperty {
private String url;
private String address;
}

@Configuration
@EnableConfigurationProperties(StarConfigProperty.class)
public class StarConfiguration {
}

@Slf4j
@SpringBootApplication
public class ApplicationSpringBootExample01 {

@Resource
StarConfigProperty starConfigProperty;

public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(ApplicationSpringBootExample01.class, args);
ApplicationSpringBootExample01 applicationContextBean = applicationContext.getBean(ApplicationSpringBootExample01.class);
applicationContextBean.process();
}

private void process() {
log.info("starConfigProperty:[{}]", starConfigProperty);
}
}

4. 启动时配置校验

配置内容如下:

1
2
3
4
5
6
7
8
# 测试配置校验
test:
validation:
myName: cyx
myBean:
name: ccc
age: 22
# address: nanjing

测试代码:

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
@Data
@Validated
@Configuration
@ConfigurationProperties(prefix = "test.validation")
public class ValidationConfiguration {
@NotBlank(message = "参数为空")
private String myName;
@Valid
private MyBean myBean;
@Data
@Accessors(chain = true)
public static class MyBean {
@NotBlank(message = "name为空")
private String name;
@NotNull(message = "age为空")
private Integer age;
@NotBlank(message = "address为空")
private String address;
}
}

@Slf4j
@SpringBootApplication
public class ApplicationSpringBootExample01 {

public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(ApplicationSpringBootExample01.class, args);
ApplicationSpringBootExample01 applicationContextBean = applicationContext.getBean(ApplicationSpringBootExample01.class);
applicationContextBean.process();
}

@Resource
ValidationConfiguration validationConfiguration;
private void process() {
log.info("validationConfiguration:[{}]", validationConfiguration);
}
}

通过在字段上添加 validation 相关注解,同时在类上添加 @Validated 注解,就可以在配置参数传入到应用中时进行有效的校验。

测试结果如下:

1
2
3
4
5
6
7
8
Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'test.validation' to com.yxcheng.configuration.module08.ValidationConfiguration$$EnhancerBySpringCGLIB$$23b5265b failed:

Property: test.validation.myBean.address
Value: null
Reason: address为空

Action:
Update your application's configuration

5. 复杂类型

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# application.yml
spring:
profiles:
active: dev
# active: prod
application:
name: springboot-example-01

server:
port: 9401
servlet:
context-path: /api

# application-dev.yml
star:
url: www.google.com
address: 南京
historyProperties:
version: 5
pathOrUrl: C\:/Library/maven_repository
dataDirName: data1
kind: LOCAL
lastUpdate: 1604987319723
id: local
locations: 中山陵,新街口,河西中央公园
relations:
aaa:
- $.services[key='dev111'].configs.providers.dialects.voices.voice[code='%s']
bbb:
- $.services[key='dev111'].configs.settings.disabasdledSasdkills.skill[code='%s']
- $.services[key='dev111'].configs.settings.alwasddysMaatchStatementSkills[code='%s']
- $.services[key='dev111'].configs.providers.includedSkills.staasdndardfasSkfsaill[code='%s']
- $.services[key='dev111'].configs.skill[code='%s']

# application-prod.yml
star:
url: www.baidu.com
address: 北京
historyProperties:
version: 6
pathOrUrl: C\:/Library/maven_repository
dataDirName: data2
kind: LOCAL2
lastUpdate: 1604987319723-2
id: local-2
locations: 天安门,天坛,人民大会堂,国家博物馆
relations:
aaa:
- $.services[key='dev222'].configs.providers.dialects.voices.voice[code='%s']
bbb:
- $.services[key='dev222'].configs.settings.disabasdledSasdkills.skill[code='%s']
- $.services[key='dev222'].configs.settings.alwasddysMaatchStatementSkills[code='%s']
- $.services[key='dev222'].configs.providers.includedSkills.staasdndardfasSkfsaill[code='%s']
- $.services[key='dev222'].configs.skill[code='%s']

相关测试代码:

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
@Data
@Configuration
@ConfigurationProperties(prefix = "star")
public class StarConfigProperty {
private String url;
private String address;
private Map<String, String> historyProperties = new HashMap<>();
private List<String> locations = new ArrayList<>();
private Map<String, List<String>> relations;
}

@Slf4j
@SpringBootApplication
public class ApplicationSpringBootExample01 {

@Resource
StarConfigProperty starConfigProperty;

public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(ApplicationSpringBootExample01.class, args);
ApplicationSpringBootExample01 applicationContextBean = applicationContext.getBean(ApplicationSpringBootExample01.class);
applicationContextBean.process();
}

private void process() {
log.info("starConfigProperty:[{}]", starConfigProperty);
}
}

6. AutoConfigureBefore相关注解使用

AutoConfigureBefore、AutoConfigureAfter、AutoConfigureOrder 三个注解的使用。

先说结论:这三个注解 在自动配置中使用,即:封装自定义 starter 中使用,而不是在业务工程中的@Configuration 配置类里使用,那会毫无效果

You can use the @AutoConfigureAfter or @AutoConfigureBefore annotations if your configuration needs to be applied in a specific order. For example, if you provide web-specific configuration, your class may need to be applied after WebMvcAutoConfiguration.

If you want to order certain auto-configurations that should not have any direct knowledge of each other, you can also use @AutoConfigureOrder. That annotation has the same semantic as the regular @Order annotation but provides a dedicated order for auto-configuration classes.

49.2 Locating Auto-configuration Candidates


6.1. 使用

先添加一个普通配置类,这个类放在 springboot 主类可以扫描到的包中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Data
@Slf4j
@Configuration
@ConfigurationProperties(prefix = "star")
public class StarConfig {
public StarConfig() {
log.info("我是被自动扫描的配置类 star,初始化啦....");
}

private String url;
private String address;
private Map<String, String> historyProperties = new HashMap<>();
private List<String> locations = new ArrayList<>();
private Map<String, List<String>> relations;
}

下面这两个类用来模拟需要先后加载的配置类,注意:这两个配置类需要放在 springboot 主类扫描不到的包中!

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
@Data
@Slf4j
@Configuration
@AutoConfigureBefore(DataBaseConfig.class)
// @AutoConfigureAfter(DataBaseConfig.class)
@ConfigurationProperties(prefix = "example.redis")
public class RedisConfig {
RedisConfig() {
log.info("配置类 redis 构造器被执行...");
}
private Integer database;
private String host;
private Integer port;
private Long timeout;
}

@Data
@Slf4j
@Configuration
@ConfigurationProperties(prefix = "example.database")
public class DataBaseConfig {
DataBaseConfig() {
log.info("配置类 database 构造器被执行...");
}
private String url;
private String username;
private String passwrod;
}

然后在 resource/META-INF/spring.factories 文件中添加这两个类的路径:

1
2
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
external.DataBaseConfig,external.RedisConfig

运行看结果:

1
2
3
我是被自动扫描的配置类 star,初始化啦....
配置类 redis 构造器被执行...
配置类 database 构造器被执行...

RedisConfig 先于 DataBaseConfig 被加载。


模拟测试需要注意:

  1. 要把 RedisConfig 和 DataBaseConfig 这两个类挪动到 SpringBootApplication(主类) 扫描不到的包内,切记:一定且必须是扫描不到的包内
  2. 当前工程中 resources/META-INF/spring.factories 文件中内容的前后顺序对结果无影响。

StarConfig 配置类会被优先加载,SpringBoot 的自动配置均是通过 resources/META-INF/spring.factories 文件来指定的,它的优先级最低(执行时机是最晚的);基于 SpringBootApplication(主类) 下自动扫描进来的类优先级是最高的。


7. 关于bootstrap.yml

SpringBoot 项目中如果没有依赖 spring-cloud-context 的话,是不会读取 bootstrap.yml 文件

bootstrap.yml 配置是 SpringCloud 项目才会用到的,如果项目仅仅是一个 SpringBoot 项目,只会识别 application.yml 配置文件。

由于 SpringCloud 是基于 SpringBoot 构建的,所有 SpringCloud 项目两种文件都会识别,这个时候才有优先级的说法,SpringCloud 项目是会优先读取 bootstrap.yml 配置,再读取 application.yml 配置。


8. 依赖POM

以上示例的依赖

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<dependencies>
<!--starter-->
<dependency>
<groupId> org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</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>

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

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

<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
</dependencies>

9. Reference