之前我们学习了在 Spring Boot 如何读取 application.properties/application.yaml 配置文件的配置信息,在上文中我们主要是简单地实践了些简单的设置,这次我们带着同样的问题,如果配置更加复杂,我们的配置读取又应该怎么处理呢。
本文的学习主要基于 Spring Boot 自带的库来解析配置,我们只是加了个 lombok 库方便我们 @Data,这样就不用在 Bean 上写那么多代码。
话不多说,开干。
环境:
- Spring Boot:3.1.6
- JDK: 17
依赖
xml
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
接下来的配置解析上,我们主要分是否嵌套的配置项,以及通过 @ConfigurationProperties 和 @Value 来处理。
1.简单配置
对于简单的配置,我们通常稍加代码,就解决了。
application.yaml
yaml
app:
version: 1.0.0
name: my config
通过@ConfigurationProperties读取配置
java
package com.example.springbootconfigrddemo.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* 自定义配置读取
*/
@Configuration
@ConfigurationProperties(prefix = "app")
@Data
public class ConfigPropertiesLoad {
private String version;
private String name;
}
测试读取配置
java
package com.example.springbootconfigrddemo.controller;
import com.example.springbootconfigrddemo.config.ConfigPropertiesLoad;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class ConfigPropertiesLoadController {
@Autowired
private ConfigPropertiesLoad cfgProperties;
@GetMapping("/configProperties")
public Object configProperties() {
Map<String, Object> info = new HashMap<>();
info.put("name", cfgProperties.getName());
info.put("version", cfgProperties.getVersion());
return info;
}
}
通过@Value读取配置
java
package com.example.springbootconfigrddemo.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
@Component
@PropertySource(value = "classpath:application.yaml")
@Data
public class ValueReadConfig {
@Value("${app.version}")
private String version;
@Value("${app.name}")
private String name;
}
测试读取配置
java
package com.example.springbootconfigrddemo.controller;
import com.example.springbootconfigrddemo.config.ValueReadConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class ValueReadConfigController {
@Autowired
private ValueReadConfig config;
@GetMapping("/valueConfig")
public Object valueConfig() {
Map<String, Object> info = new HashMap<>();
info.put("name", config.getName());
info.put("version", config.getVersion());
return info;
}
}
2.带嵌套的配置
自定义的配置项多级嵌套,application.yaml:
yaml
app1:
name: app1 introduction
info:
author: admin
desc: It's a config demo
通过@ConfigurationProperties读取配置
InfoConfig.java
java
package com.example.springbootconfigrddemo.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "app1.info")
public class InfoConfig {
private String author;
private String desc;
}
ConfigPropertiesMultiLevelLoad.java
java
package com.example.springbootconfigrddemo.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* 自定义嵌套配置读取
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "app1")
public class ConfigPropertiesMultiLevelLoad {
private String name;
@Autowired
private InfoConfig info;
}
测试读取配置
java
package com.example.springbootconfigrddemo.controller;
import com.example.springbootconfigrddemo.config.ConfigPropertiesMultiLevelLoad;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class ConfigPropertiesMultiLevelController {
@Autowired
private ConfigPropertiesMultiLevelLoad config;
@GetMapping("/configMultiLevel")
public Object configMultiLevel() {
Map<String, Object> ret = new HashMap<>();
Map<String, Object> info = new HashMap<>();
info.put("author", config.getInfo().getAuthor());
info.put("desc", config.getInfo().getDesc());
ret.put("name", config.getName());
ret.put("info", info);
return ret;
}
}
通过@Value读取配置
配置读取
java
package com.example.springbootconfigrddemo.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
@Component
@PropertySource(value = "classpath:application.yaml")
@Data
public class ValueMultiReadConfig {
@Value("${app1.name}")
private String name;
@Value("${app1.info.author}")
private String author;
@Value("${app1.info.desc}")
private String desc;
}
测试读取配置
java
package com.example.springbootconfigrddemo.controller;
import com.example.springbootconfigrddemo.config.ValueMultiReadConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class ValueMultiReadConfigController {
@Autowired
private ValueMultiReadConfig config;
@GetMapping("/valueMultiLevel")
public Object valueMultiReadConfig() {
Map<String, Object> ret = new HashMap<>();
Map<String, Object> info = new HashMap<>();
info.put("author", config.getAuthor());
info.put("desc", config.getDesc());
ret.put("name", config.getName());
ret.put("info", info);
return ret;
}
}
3.带多级嵌套的配置
如果嵌套级数更多呢,这里我们怎么处理呢,这里以 Redis配置 为例,返回 Redis的配置项参数,application.yaml:
yaml
spring:
data:
redis:
port: 6379
host: localhost
database: 1
jedis:
pool:
enabled: true
max-active: 8
max-idle: 8
min-idle: 1
通过@ConfigurationProperties读取配置
由于是多级嵌套,我们从最内层到最外层开始编码实现,通过 @AutoWired 一层层自动装配。
Pool.java
java
package com.example.springbootconfigrddemo.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "spring.data.redis.jedis.pool")
public class Pool {
private boolean enabled;
private int maxActive;
private int maxIdle;
private int minIdle;
}
Jedis.java
java
package com.example.springbootconfigrddemo.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "spring.data.redis.jedis")
public class Jedis {
@Autowired Pool pool;
}
Redis.java
java
package com.example.springbootconfigrddemo.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "spring.data.redis")
public class Redis {
private int port;
private String host;
private int database;
@Autowired
private Jedis jedis;
@Override
public String toString() {
return String.format("Redis{host=%s, port=%d, database=%d, jedis{enabled=%b, maxActive=%d, maxIdle=%d, minIdle=%d}}",
host, port, database, jedis.pool.isEnabled(), jedis.pool.getMaxActive(),
jedis.pool.getMaxIdle(), jedis.pool.getMinIdle());
}
}
测试读取配置
java
package com.example.springbootconfigrddemo.controller;
import com.example.springbootconfigrddemo.config.Redis;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class RedisConfigController {
@Autowired
private Redis redis;
@GetMapping("/redisConfig")
public Object redisConfig() {
return redis.toString();
}
}
通过@Value读取配置
java
package com.example.springbootconfigrddemo.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableAutoConfiguration
@Data
public class PoolConfig {
@Value("${spring.data.redis.host}")
private String host;
@Value("${spring.data.redis.port}")
private int port;
@Value("${spring.data.redis.database}")
private int database;
@Value("${spring.data.redis.jedis.pool.min-idle}")
private int minIdle;
@Value("${spring.data.redis.jedis.pool.max-active}")
private int maxActive;
@Value("${spring.data.redis.jedis.pool.max-idle}")
private int maxIdle;
@Value("${spring.data.redis.jedis.pool.enabled}")
private boolean enabled;
@Override
public String toString() {
return String.format("Pool{host=%s, port=%d, database=%d, maxIdle=%d, maxActive=%d, minIdle=%d, enabled=%b}", host, port, database, maxIdle, maxActive, minIdle, enabled);
}
}
测试读取配置
java
package com.example.springbootconfigrddemo.controller;
import com.example.springbootconfigrddemo.config.PoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PoolController {
@Autowired
private PoolConfig pool;
@GetMapping("/poolConfig")
public String poolConfig() {
return pool.toString();
}
}
总结
上面我们通过 @ConfigurationProperties 和 @Value 两种方法获取配置,前者读取配置需要注意嵌套的配置需要加一层,通过 @AutoWired 自动装配进来,后者则是通过字段全部展平赋值,如果很多级的情况下,用 @Value 实现的代码更加简洁,而使用 @ConfigurationProperties 则需要层层 AutoWired 。
总的来说,上面两种方法是我们日常开发中使用较多的配置读取的方案,有的方案是通过其他 yaml 三方库获取配置,当然也可以,方法不止一种,但从项目开发角度,怎么方便怎么简洁怎么来,毕竟快速开发业务更加重要。
参考: