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
相关产品推荐
相关产品推荐

