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

如何在Spring Profile的@PropertySource处理后执行EnvironmentPostProcessor

问题根源分析

你遇到的核心问题是执行时机不匹配:EnvironmentPostProcessor是在Spring Boot启动的prepareEnvironment阶段执行的,此时ApplicationContext还未创建,带@Profile("development")和@PropertySource的DevelopmentConfiguration类还没被解析,那些properties文件里的属性根本没加载到Environment中,自然拿不到。

下面提供两种实用解决方案:

方案一:在EnvironmentPostProcessor中手动加载Profile对应的PropertySource

既然Spring Boot还没加载这些文件,我们可以在处理器里检测到development Profile激活时,主动把这些PropertySource加载到Environment中,之后再执行属性替换逻辑。

代码实现

public class CustomEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {

    private static final String DEVELOPMENT_PROFILE = "development";
    private final PropertySourceLoader propertySourceLoader = new PropertiesPropertySourceLoader();

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        // 检查是否激活了development Profile
        if (Arrays.asList(environment.getActiveProfiles()).contains(DEVELOPMENT_PROFILE)) {
            try {
                // 依次加载三个配置文件
                loadPropertySource(environment, new ClassPathResource("development.properties"), "dev-classpath");
                loadPropertySource(environment, new ClassPathResource("development-logging.properties"), "dev-log-classpath");
                loadPropertySource(environment, new FileSystemResource("./local-development-configuration.properties"), "dev-local-file");
            } catch (IOException e) {
                throw new IllegalStateException("加载development Profile配置文件失败", e);
            }

            // 执行你的属性替换逻辑,此时已能获取到上述文件的属性
            replaceTargetProperties(environment);
        }
    }

    private void loadPropertySource(ConfigurableEnvironment environment, Resource resource, String sourceName) throws IOException {
        if (resource.exists()) {
            List<PropertySource<?>> sources = propertySourceLoader.load(sourceName, resource);
            sources.forEach(source -> environment.getPropertySources().addLast(source));
        }
    }

    private void replaceTargetProperties(ConfigurableEnvironment environment) {
        // 示例:根据源属性替换目标属性
        String sourceValue = environment.getProperty("app.source.property");
        if (sourceValue != null) {
            ((MutablePropertySources) environment.getPropertySources()).addFirst(
                new MapPropertySource("custom-property-override", 
                    Collections.singletonMap("app.target.property", sourceValue))
            );
        }
    }

    @Override
    public int getOrder() {
        // 设置执行顺序,确保在Spring Boot默认处理器之后,ApplicationContext创建之前
        return Ordered.LOWEST_PRECEDENCE - 10;
    }
}

注册处理器

在项目的META-INF/spring.factories文件中添加以下配置,让Spring Boot识别这个处理器:

org.springframework.boot.env.EnvironmentPostProcessor=com.your.package.CustomEnvironmentPostProcessor

方案二:改用ApplicationContextInitializer(适合时机要求宽松的场景)

如果你的属性替换不需要在最早期的环境准备阶段完成,可以改用ApplicationContextInitializer——它会在ApplicationContext创建完成但未执行refresh时触发,此时@PropertySource的属性已经加载到Environment中了。

代码实现

public class CustomApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    private static final String DEVELOPMENT_PROFILE = "development";

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        if (Arrays.asList(environment.getActiveProfiles()).contains(DEVELOPMENT_PROFILE)) {
            // 直接执行属性替换,此时已能获取到DevelopmentConfiguration加载的属性
            replaceTargetProperties(environment);
        }
    }

    private void replaceTargetProperties(ConfigurableEnvironment environment) {
        // 这里写你的属性替换逻辑,和方案一的替换逻辑一致即可
        String sourceValue = environment.getProperty("app.source.property");
        if (sourceValue != null) {
            ((MutablePropertySources) environment.getPropertySources()).addFirst(
                new MapPropertySource("custom-property-override", 
                    Collections.singletonMap("app.target.property", sourceValue))
            );
        }
    }
}

注册初始化器

同样在META-INF/spring.factories中配置:

org.springframework.context.ApplicationContextInitializer=com.your.package.CustomApplicationContextInitializer

方案选择建议

  • 方案一:属性替换时机早,所有依赖环境属性的Bean初始化时都能拿到替换后的值,适合对属性生效时机要求严格的场景;
  • 方案二:无需手动加载配置文件,实现更简单,但时机稍晚,适合对属性生效时机要求不高的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 01:54:14