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

参考:

相关推荐
苏三的开发日记28 分钟前
linux搭建hadoop服务
后端
sir76144 分钟前
Redisson分布式锁实现原理
后端
大学生资源网1 小时前
基于springboot的万亩助农网站的设计与实现源代码(源码+文档)
java·spring boot·后端·mysql·毕业设计·源码
苏三的开发日记1 小时前
linux端进行kafka集群服务的搭建
后端
苏三的开发日记2 小时前
windows系统搭建kafka环境
后端
爬山算法2 小时前
Netty(19)Netty的性能优化手段有哪些?
java·后端
Tony Bai2 小时前
Cloudflare 2025 年度报告发布——Go 语言再次“屠榜”API 领域,AI 流量激增!
开发语言·人工智能·后端·golang
想用offer打牌2 小时前
虚拟内存与寻址方式解析(面试版)
java·后端·面试·系统架构
無量2 小时前
AQS抽象队列同步器原理与应用
后端
9号达人3 小时前
支付成功订单却没了?MyBatis连接池的坑我踩了
java·后端·面试