微服务: ConfigurationProperties配置

简介

我们在开发的时候,可能会遇到这样的场景:

变量希望能够被在配置文件中动态配置,只要修改这些配置,对应的 Java 类对象的变量值就可以改变,从而改变代码的行为。这样我们通过修改配置就可以满足业务诉求,而不需要修改一行代码。

在 SpringBoot 中,可以通过 @ConfigurationProperties@Values 两个注解配合 properties 文件达到上述目的。

比如我的 application.properties 文件配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# ------------------------
# Swagger config
# ------------------------
msconfig.swagger.enableSwagger=true
# ------------------------
# Security config
# ------------------------
msconfig.security.enableCSRF=false
msconfig.security.defToken="token-xx-yy-kk-token-end"
msconfig.security.testList[0]="list0"
msconfig.security.testList[1]="list1"
msconfig.security.testList[2]="list2"
msconfig.security.testMap.KeyTest="map-key"
msconfig.security.testMap.ValueTest="map-value"

接下来,通过 @ConfigurationProperties@Values 来分别读取对应的配置。

本文涉及的代码都已经更新到 Github 工程 中了,大家可以下载查看。

关于微服务的相关文章目录,可以☞ 点我) 查看更多内容。

ConfigurationProperties

对应的,新建两个实体类,如下图所示:

实体类 MSSecurityPropertyConfigModel 的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
@Component
@Setter
@Getter
@ConfigurationProperties(prefix = "msconfig.security")
public class MSSecurityPropertyConfigModel {
private boolean enableCSRF;
private String defToken;
// List的配置
private List testList;
// Map的配置
private Map testMap;
}

这里需要注意以下几个问题

1、必须提供 setter 方法,这里我使用了 lombok

2、必须使用 @Component 注解,标注在实体类上面;

3、在 @ConfigurationPropertiesprefix 中必须和配置文件命名保持一致;

4、需要在类上加上 @Component 注解;

关于 MSSwaggerPropertyConfigModel 大家可以自行查看代码,这里不再赘述。

写个测试类,验证一下配置。

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
@RunWith(SpringRunner.class)
@SpringBootTest
public class MSPropertyConfigTests {
@Autowired
MSSwaggerPropertyConfigModel swaggerPropertyConfigModel;
@Autowired
MSSecurityPropertyConfigModel securityPropertyConfigModel;
private Logger logger = LoggerFactory.getLogger(MSPropertyConfigTests.class);
@Test
public void primitiveDataConfig() {
boolean enableSwagger = swaggerPropertyConfigModel.isEnableSwagger();
boolean enableCSRF = securityPropertyConfigModel.isEnableCSRF();
logger.info("primitiveDataConfig-enableSwagger: " + enableSwagger + ", enableCSRF: " + enableCSRF);
String defToken = securityPropertyConfigModel.getDefToken();
logger.info("securityPropertyConfigModel deftoken: " + defToken);
List list = securityPropertyConfigModel.getTestList();
for (Object v : list) {
logger.info("securityPropertyConfigModel value: " + v);
}
Map map = securityPropertyConfigModel.getTestMap();
logger.info("securityPropertyConfigModel map: " + map);
}
}

执行该测试方法,得到如下的输出内容:

1
2
3
4
5
6
primitiveDataConfig-enableSwagger: true, enableCSRF: false
securityPropertyConfigModel deftoken: "token-xx-yy-kk-token-end"
securityPropertyConfigModel value: "list0"
securityPropertyConfigModel value: "list1"
securityPropertyConfigModel value: "list2"
securityPropertyConfigModel map: {KeyTest="map-key", ValueTest="map-value"}

如果您在使用 @ConfigurationProperties 注解过程中,提示如下错误:

1
“Spring Boot Configuration Annotation Processor not found in classpath ”

此时需要在你的 pom.xml 文件中引进 configuration-processor 依赖即可解决。

1
2
3
4
5
6
<!--ConfigurationProperties-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

Value

使用 @Values 注解可以直接作用到某个类的某个字段上面,使用上面比较方便。

对于读取集合的方法跟 @ConfigurationProperties 注解有点不同。

application.properties 文件中增加 testList1testMap1 配置如下:

1
2
3
4
5
6
7
8
9
# ------------------------
# Security config
# ------------------------
msconfig.security.enableCSRF=false
msconfig.security.defToken="token-xx-yy-kk-token-end"
msconfig.security.testList1=list0,list1,list2
msconfig.security.testMap1={name:"map-key", age:20}

注意:在配置文件中的 testList1testMap1 配置格式和之前的不一样,否则解析会报错。

测试类中验证,示例代码如下,注意 @Values 注解对集合的书写格式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Value("${msconfig.security.enableCSRF}")
private boolean geEnableCSRF;
@Value("${msconfig.security.defToken}")
private String defUserToken;
@Value("#{'${msconfig.security.testList1}'.split(',')}")
private List list1;
@Value("#{${msconfig.security.testMap1}}")
private Map map1;
@Test
public void primitiveDataConfig() {
logger.info("annotation value. geEnableCSRF: " + geEnableCSRF);
logger.info("annotation value. defUserToken: " + defUserToken);
for (Object v : list1) {
logger.info("annotation value. list: " + v);
}
logger.info("annotation value. map: " + map1);
}

读取结果如下:

1
2
3
4
5
6
annotation value. geEnableCSRF: false
annotation value. defUserToken: "token-xx-yy-kk-token-end"
annotation value. list: list0
annotation value. list: list1
annotation value. list: list2
annotation value. map: {name=map-key, age=20}

我们也可以将 @ConfigurationProperties@Values 这两个注解配合使用。

1
msconfig.security.alias="play-game"

在代码中重新定义变量名称为 aliasPlayGame,可以使用 @Values 定位实际配置的变量名称。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Component
@Setter
@Getter
@ConfigurationProperties(prefix = "msconfig.security")
public class MSSecurityPropertyConfigModel {
private boolean enableCSRF;
private String defToken;
private List testList;
private Map testMap;
// 和 ConfigurationProperties 一起使用
@Value("msconfig.security.alias")
private String aliasPlayGame;
}

你以为的不一定是你以为的

坚持原创技术分享!