You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求SpringBoot读取解析ConfigurationProperties的代码及独立模块实现指引

实现独立的SpringBoot风格配置解析工具

要实现一个能像SpringBoot那样解析application.properties/application.yml,并支持系统属性、环境变量覆盖的独立配置解析工具,核心是复用Spring的配置绑定组件,同时剥离SpringBoot的自动装配逻辑。下面是完整的实现方案:

1. 依赖准备(Maven)

只需要引入必要的Spring核心依赖和YAML解析库:

<dependencies>
    <!-- Spring配置绑定核心依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <exclusions>
            <!-- 移除日志依赖,按需添加 -->
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <!-- YAML文件解析依赖 -->
    <dependency>
        <groupId>org.yaml</groupId>
        <artifactId>snakeyaml</artifactId>
        <version>2.2</version>
    </dependency>
</dependencies>

2. 定义配置类

用SpringBoot的@ConfigurationProperties注解标记配置类,指定前缀并定义对应字段(必须提供getter/setter):

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "app")
public class Config {
    private String name;
    private int port;
    private Database database;

    // 必须添加getter和setter,否则绑定失败
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getPort() { return port; }
    public void setPort(int port) { this.port = port; }
    public Database getDatabase() { return database; }
    public void setDatabase(Database database) { this.database = database; }

    @Override
    public String toString() {
        return "Config{" +
                "name='" + name + '\'' +
                ", port=" + port +
                ", database=" + database +
                '}';
    }

    public static class Database {
        private String url;
        private String username;
        private String password;

        // 同样需要getter和setter
        public String getUrl() { return url; }
        public void setUrl(String url) { this.url = url; }
        public String getUsername() { return username; }
        public void setUsername(String username) { this.username = username; }
        public String getPassword() { return password; }
        public void setPassword(String password) { this.password = password; }

        @Override
        public String toString() {
            return "Database{" +
                    "url='" + url + '\'' +
                    ", username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    '}';
        }
    }
}

3. 核心解析工具类

实现parseConfig方法,完成配置文件加载、环境变量/系统属性整合、配置绑定:

import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.yaml.snakeyaml.Yaml;

import java.io.IOException;
import java.util.Map;
import java.util.Properties;

public class ConfigParser {

    public static <T> T parseConfig(Class<T> configClass) {
        // 初始化标准环境,自动包含系统属性(systemProperties)和环境变量(systemEnvironment)
        StandardEnvironment environment = new StandardEnvironment();
        MutablePropertySources propertySources = environment.getPropertySources();

        // 加载classpath下的配置文件,不存在则跳过
        loadPropertiesFile("application.properties", propertySources);
        loadYamlFile("application.yml", propertySources);

        // 使用Spring的Binder完成配置绑定
        Binder binder = new Binder(ConfigurationPropertySources.from(environment));
        return binder.bind("", Bindable.of(configClass))
                .orElseThrow(() -> new RuntimeException("配置绑定失败,请检查配置类和配置文件"));
    }

    private static void loadPropertiesFile(String fileName, MutablePropertySources propertySources) {
        Resource resource = new ClassPathResource(fileName);
        if (!resource.exists()) return;

        try {
            Properties props = PropertiesLoaderUtils.loadProperties(resource);
            propertySources.addLast(new org.springframework.core.env.PropertiesPropertySource(fileName, props));
        } catch (IOException e) {
            throw new RuntimeException("加载properties文件失败:" + fileName, e);
        }
    }

    private static void loadYamlFile(String fileName, MutablePropertySources propertySources) {
        Resource resource = new ClassPathResource(fileName);
        if (!resource.exists()) return;

        try {
            Yaml yaml = new Yaml();
            Map<String, Object> yamlMap = yaml.load(resource.getInputStream());
            // 将嵌套的YAML结构扁平化为Spring支持的键值对格式
            Properties props = new Properties();
            flattenYaml("", yamlMap, props);
            propertySources.addLast(new org.springframework.core.env.PropertiesPropertySource(fileName, props));
        } catch (IOException e) {
            throw new RuntimeException("加载yaml文件失败:" + fileName, e);
        }
    }

    private static void flattenYaml(String prefix, Map<String, Object> yamlMap, Properties props) {
        for (Map.Entry<String, Object> entry : yamlMap.entrySet()) {
            String key = prefix.isEmpty() ? entry.getKey() : prefix + "." + entry.getKey();
            if (entry.getValue() instanceof Map) {
                flattenYaml(key, (Map<String, Object>) entry.getValue(), props);
            } else {
                props.setProperty(key, entry.getValue().toString());
            }
        }
    }
}

4. 使用示例

直接调用parseConfig方法即可获取绑定好的配置实例:

public class App {
    public static void main(String[] args) {
        var config = ConfigParser.parseConfig(Config.class);
        System.out.println("加载的配置:" + config);
    }
}

配置优先级说明

按照Spring的规则,配置覆盖优先级从高到低为:

  • 系统属性(如启动时添加-Dapp.name=test)
  • 环境变量(如设置APP_NAME=test)
  • application.yml
  • application.properties

如果同一配置项在多个地方存在,高优先级的配置会覆盖低优先级的。

内容的提问来源于stack exchange,提问作者morpheus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 22:50:42