全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-18 8 分钟 ✍️ juanwangdev

Spring Boot EnvironmentPostProcessor扩展

EnvironmentPostProcessor 允许在应用启动早期修改环境配置。

接口定义

Java
@FunctionalInterface
public interface EnvironmentPostProcessor {
    void postProcessEnvironment(ConfigurableEnvironment environment,
                                SpringApplication application);
}

执行时机

Java
ApplicationStartingEvent
  → EnvironmentPostProcessor ← 此时执行
  → ApplicationEnvironmentPreparedEvent
  → ApplicationContextInitializedEvent
  → ApplicationPreparedEvent
  → ApplicationStartedEvent

基础实现

properties
public class CustomEnvironmentPostProcessor implements EnvironmentPostProcessor {

    @Override
    public void postProcessEnvironment(
            ConfigurableEnvironment environment,
            SpringApplication application) {

        // 添加自定义属性
        Map<String, Object> customProps = new HashMap<>();
        customProps.put("app.custom.name", "my-app");
        customProps.put("app.custom.version", "1.0.0");

        environment.getPropertySources()
            .addFirst(new MapPropertySource("custom-props", customProps));
    }
}

注册处理器

方式一:spring.factories

properties
# META-INF/spring.factories
org.springframework.boot.env.EnvironmentPostProcessor=\
com.example.CustomEnvironmentPostProcessor

方式二:Spring Boot 2.4+ Import

Java
# META-INF/spring/org.springframework.boot.env.EnvironmentPostProcessor.imports
com.example.CustomEnvironmentPostProcessor

从数据库加载配置

Java
public class DatabaseConfigPostProcessor implements EnvironmentPostProcessor {

    @Override
    public void postProcessEnvironment(
            ConfigurableEnvironment environment,
            SpringApplication application) {

        // 先获取数据库连接信息
        String url = environment.getProperty("spring.datasource.url");
        String username = environment.getProperty("spring.datasource.username");
        String password = environment.getProperty("spring.datasource.password");

        if (url == null) {
            return;  // 未配置数据源则跳过
        }

        // 从数据库加载配置
        Map<String, Object> dbConfig = loadFromDatabase(url, username, password);

        // 添加到环境
        environment.getPropertySources()
            .addAfter("applicationConfig: [classpath:/application.yml]",
                new MapPropertySource("database-config", dbConfig));
    }

    private Map<String, Object> loadFromDatabase(
            String url, String username, String password) {
        Map<String, Object> config = new HashMap<>();
        try (Connection conn = DriverManager.getConnection(url, username, password);
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery("SELECT key, value FROM config")) {
            while (rs.next()) {
                config.put(rs.getString("key"), rs.getString("value"));
            }
        } catch (SQLException e) {
            throw new RuntimeException("加载数据库配置失败", e);
        }
        return config;
    }
}

加密配置解密

Java
public class DecryptEnvironmentPostProcessor implements EnvironmentPostProcessor {

    private static final String PREFIX = "ENC(";
    private static final String SUFFIX = ")";

    @Override
    public void postProcessEnvironment(
            ConfigurableEnvironment environment,
            SpringApplication application) {

        environment.getPropertySources().forEach(source -> {
            if (source instanceof EnumerablePropertySource) {
                EnumerablePropertySource<?> eps = (EnumerablePropertySource<?>) source;
                Map<String, Object> decrypted = new HashMap<>();

                for (String name : eps.getPropertyNames()) {
                    Object value = eps.getProperty(name);
                    if (value instanceof String) {
                        decrypted.put(name, decryptIfNeeded((String) value));
                    }
                }

                // 替换原配置
                environment.getPropertySources()
                    .replace(source.getName(),
                        new MapPropertySource(source.getName(), decrypted));
            }
        });
    }

    private String decryptIfNeeded(String value) {
        if (value.startsWith(PREFIX) && value.endsWith(SUFFIX)) {
            String encrypted = value.substring(
                PREFIX.length(), value.length() - SUFFIX.length());
            return AESUtil.decrypt(encrypted);
        }
        return value;
    }
}

多环境配置合并

text
public class ProfileMergePostProcessor implements EnvironmentPostProcessor {

    @Override
    public void postProcessEnvironment(
            ConfigurableEnvironment environment,
            SpringApplication application) {

        String[] activeProfiles = environment.getActiveProfiles();

        Map<String, Object> mergedConfig = new HashMap<>();

        // 按优先级加载配置
        for (String profile : activeProfiles) {
            String location = "classpath:config-" + profile + ".properties";
            try {
                Resource resource = new ClassPathResource(location);
                if (resource.exists()) {
                    Properties props = PropertiesLoaderUtils.loadProperties(resource);
                    props.forEach((k, v) -> mergedConfig.put(k.toString(), v));
                }
            } catch (IOException e) {
                // 忽略不存在的配置
            }
        }

        environment.getPropertySources()
            .addLast(new MapPropertySource("merged-profile-config", mergedConfig));
    }
}

PropertySources顺序

顺序PropertySource说明
1commandLineArgs命令行参数
2systemProperties系统属性
3systemEnvironment环境变量
4application.yml配置文件
5defaultProperties默认属性

addFirst添加到最前面优先级最高,addLast添加到最后优先级最低。

要点总结

  • EnvironmentPostProcessor在应用启动早期执行
  • 通过spring.factories或imports文件注册
  • 可用于动态加载、解密、合并配置
  • 注意PropertySources顺序决定优先级

📝 发现内容有误?点击此处直接编辑

← 上一篇 Spring Boot BeanPostProcessor扩展
下一篇 → Spring Boot FailureAnalyzer自定义
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库