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 | 说明 |
|---|---|---|
| 1 | commandLineArgs | 命令行参数 |
| 2 | systemProperties | 系统属性 |
| 3 | systemEnvironment | 环境变量 |
| 4 | application.yml | 配置文件 |
| 5 | defaultProperties | 默认属性 |
addFirst添加到最前面优先级最高,addLast添加到最后优先级最低。
要点总结
- EnvironmentPostProcessor在应用启动早期执行
- 通过spring.factories或imports文件注册
- 可用于动态加载、解密、合并配置
- 注意PropertySources顺序决定优先级
📝 发现内容有误?点击此处直接编辑