Java Spring Boot 配置读取进阶篇-@ConfigurationProperties && @Value

之前我们学习了在 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 三方库获取配置,当然也可以,方法不止一种,但从项目开发角度,怎么方便怎么简洁怎么来,毕竟快速开发业务更加重要。

参考:

相关推荐
摇滚侠2 小时前
Spring Boot 3零基础教程,IOC容器中组件的注册,笔记08
spring boot·笔记·后端
程序员小凯5 小时前
Spring Boot测试框架详解
java·spring boot·后端
你的人类朋友5 小时前
什么是断言?
前端·后端·安全
程序员小凯7 小时前
Spring Boot缓存机制详解
spring boot·后端·缓存
i学长的猫7 小时前
Ruby on Rails 从0 开始入门到进阶到高级 - 10分钟速通版
后端·ruby on rails·ruby
用户21411832636027 小时前
别再为 Claude 付费!Codex + 免费模型 + cc-switch,多场景 AI 编程全搞定
后端
茯苓gao8 小时前
Django网站开发记录(一)配置Mniconda,Python虚拟环境,配置Django
后端·python·django
Cherry Zack8 小时前
Django视图进阶:快捷函数、装饰器与请求响应
后端·python·django
爱读源码的大都督8 小时前
为什么有了HTTP,还需要gPRC?
java·后端·架构
码事漫谈8 小时前
致软件新手的第一个项目指南:阶段、文档与破局之道
后端