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

Spring Boot 3.0如何基于Profile加载自定义Starter配置文件?

Spring Boot 3.0 自定义Starter自动加载配置文件实现方案

在Spring Boot 3.0中,ConfigFileApplicationListener被移除,原有的通过指定searchNames加载自定义Starter配置的方式不再适用。以下两种方案可实现Starter自动加载自身配置,无需消费方感知配置位置:

方案一:自定义EnvironmentPostProcessor直接加载配置文件

这种方式简单直观,延续Spring Boot 2.x的思路,直接在后置处理器中加载Starter的配置文件并添加到环境中。

1. 编写通用抽象后置处理器

import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.env.PropertiesPropertySourceLoader;
import org.springframework.boot.env.PropertySourceLoader;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import java.io.IOException;
import java.util.List;

public abstract class StarterEnvironmentPostProcessor implements EnvironmentPostProcessor {
    private final PropertySourceLoader loader = new PropertiesPropertySourceLoader();
    private final String starterName;

    protected StarterEnvironmentPostProcessor(String starterName) {
        this.starterName = starterName;
    }

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        // 加载基础配置文件
        loadConfigFile(environment, starterName + ".properties");
        // 加载激活Profile对应的配置文件
        for (String profile : environment.getActiveProfiles()) {
            loadConfigFile(environment, starterName + "-" + profile + ".properties");
        }
    }

    private void loadConfigFile(ConfigurableEnvironment environment, String fileName) {
        Resource resource = new ClassPathResource(fileName);
        if (!resource.exists()) {
            return;
        }
        try {
            List<PropertySource<?>> propertySources = loader.load(fileName, resource);
            for (PropertySource<?> source : propertySources) {
                // 将Starter配置添加到环境末尾,确保application配置可覆盖它(符合Spring Boot优先级规则)
                environment.getPropertySources().addLast(source);
            }
        } catch (IOException e) {
            throw new RuntimeException("加载Starter配置文件失败: " + fileName, e);
        }
    }
}

2. 每个Starter实现自己的后置处理器

public class MyStarterEnvironmentPostProcessor extends StarterEnvironmentPostProcessor {
    public MyStarterEnvironmentPostProcessor() {
        super("my-starter");
    }
}

3. 注册后置处理器

在Starter的META-INF/spring.factories文件中添加如下配置:

org.springframework.boot.env.EnvironmentPostProcessor=\
com.example.mystarter.MyStarterEnvironmentPostProcessor

该方案的优势是实现简单,完全不需要消费方做任何配置,且配置优先级符合Spring Boot的默认规则(application配置可覆盖Starter配置)。

方案二:扩展Spring Boot 3.0 ConfigData模型

该方案贴合Spring Boot 3.0新的配置体系,适合需要更灵活配置场景(如配置加密、分层加载等)。

1. 自定义ConfigData资源与解析器

// 自定义ConfigData资源
public class StarterConfigDataResource implements ConfigDataResource {
    private final String starterName;

    public StarterConfigDataResource(String starterName) {
        this.starterName = starterName;
    }

    public String getStarterName() {
        return starterName;
    }

    @Override
    public boolean isOptional() {
        return true;
    }
}

// 自定义ConfigData位置解析器
import org.springframework.boot.context.config.ConfigDataLocation;
import org.springframework.boot.context.config.ConfigDataLocationResolver;
import org.springframework.boot.context.config.ConfigDataLocationResolverContext;

import java.util.List;

public class StarterConfigDataLocationResolver implements ConfigDataLocationResolver<StarterConfigDataResource> {

    @Override
    public boolean isResolvable(ConfigDataLocationResolverContext context, ConfigDataLocation location) {
        return location.hasPrefix("starter:");
    }

    @Override
    public List<StarterConfigDataResource> resolve(ConfigDataLocationResolverContext context, ConfigDataLocation location) {
        String starterName = location.getValue().substring("starter:".length());
        return List.of(new StarterConfigDataResource(starterName));
    }
}

2. 自定义ConfigData加载器

import org.springframework.boot.context.config.ConfigData;
import org.springframework.boot.context.config.ConfigDataLoader;
import org.springframework.boot.context.config.ConfigDataLoaderContext;
import org.springframework.boot.env.PropertiesPropertySourceLoader;
import org.springframework.boot.env.PropertySourceLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class StarterConfigDataLoader implements ConfigDataLoader<StarterConfigDataResource> {
    private final PropertySourceLoader loader = new PropertiesPropertySourceLoader();

    @Override
    public ConfigData load(ConfigDataLoaderContext context, StarterConfigDataResource resource) throws IOException {
        String starterName = resource.getStarterName();
        List<PropertySource<?>> propertySources = new ArrayList<>();

        // 加载基础配置
        loadPropertySource(starterName + ".properties", propertySources);
        // 加载激活Profile的配置
        for (String profile : context.getEnvironment().getActiveProfiles()) {
            loadPropertySource(starterName + "-" + profile + ".properties", propertySources);
        }

        return new ConfigData(propertySources);
    }

    private void loadPropertySource(String fileName, List<PropertySource<?>> propertySources) throws IOException {
        Resource resource = new ClassPathResource(fileName);
        if (resource.exists()) {
            propertySources.addAll(loader.load(fileName, resource));
        }
    }
}

3. 注册ConfigData组件与配置位置

在Starter的META-INF/spring.factories中注册组件:

org.springframework.boot.context.config.ConfigDataLocationResolver=\
com.example.mystarter.StarterConfigDataLocationResolver
org.springframework.boot.context.config.ConfigDataLoader=\
com.example.mystarter.StarterConfigDataLoader

再编写一个后置处理器添加自定义配置位置:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;

import java.util.Map;

public class MyStarterConfigLocationPostProcessor implements EnvironmentPostProcessor {
    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        String existingLocations = environment.getProperty("spring.config.location", "");
        String starterLocation = "starter:my-starter";
        if (!existingLocations.contains(starterLocation)) {
            String newLocations = existingLocations.isEmpty() ? starterLocation : existingLocations + "," + starterLocation;
            environment.getPropertySources().addFirst(
                new MapPropertySource("my-starter-config-location", Map.of("spring.config.location", newLocations))
            );
        }
    }
}

同样在spring.factories中注册该后置处理器:

org.springframework.boot.env.EnvironmentPostProcessor=\
com.example.mystarter.MyStarterConfigLocationPostProcessor

总结

  • 推荐使用方案一,实现简单、轻量,完全满足Starter自动加载配置的需求,无需消费方干预。
  • 方案二更适合复杂配置场景,贴合Spring Boot 3.0的新配置模型,但实现成本较高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 21:50:32