Spring Boot 动态修改配置分启动前和运行时两种:启动前通过 ApplicationContextInitializer 在 Environment 初始化阶段注入配置;运行时通过 ConfigurableEnvironment 修改,但需配合 @RefreshScope 和 /actuator/refresh 实现 Bean 级热刷新。

Spring Boot 中通过 SpringApplication 动态修改配置,核心思路是在应用启动前(即 ApplicationContext 初始化之前)干预 Environment,向其中注入或覆盖配置项。这种方式不依赖外部配置中心,也不需要重启服务,适用于启动时从数据库、远程 API、环境变量等动态加载并生效配置。
关键点在于:必须在 ApplicationContext 创建前完成修改,否则 @Value、@ConfigurationProperties 等注解已绑定旧值,后续修改无效。
✅ 在 SpringApplication.run() 之前修改 Environment
最常用且可靠的方式是添加 ApplicationContextInitializer 或自定义 SpringApplicationRunListener,在 ApplicationEnvironmentPreparedEvent 阶段操作 MutablePropertySources。
示例:启动时从数据库加载配置并覆盖默认值
public class DatabaseConfigInitializer implements ApplicationContextInitializer<configurableapplicationcontext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
MutablePropertySources propertySources = environment.getPropertySources();
// 模拟从数据库读取 key-value 配置(注意:此处需确保 JDBC 可用,且不依赖已初始化的 DataSource Bean)
Map<string string> dbConfigs = loadFromDatabase(); // 自行实现 JDBC 查询逻辑
// 构建自定义 PropertySource 并前置插入(优先级最高)
MapPropertySource customSource = new MapPropertySource("db-config", dbConfigs);
propertySources.addFirst(customSource);
}
private Map<string string> loadFromDatabase() {
// 使用 DriverManager 或轻量 JdbcTemplate(避免依赖 Spring 容器)
// 示例 SQL:SELECT `key`, `value` FROM sys_config WHERE enabled = 1
Map<string string> map = new HashMap();
// ... 执行查询并填充 map
return map;
}
}</string></string></string></configurableapplicationcontext>
注册方式(两种均可):
-
方式一:代码中注册
public static void main(String[] args) { SpringApplication app = new SpringApplication(MyApplication.class); app.addInitializers(new DatabaseConfigInitializer()); app.run(args); } -
方式二:META-INF/spring.factories
org.springframework.context.ApplicationContextInitializer=\ com.example.DatabaseConfigInitializer
⚠️ 注意:该方法只能在启动阶段一次性加载,不是运行时热更新。若需运行时修改,请配合
ConfigurableEnvironment+MutablePropertySources.addOrReplace()(见下文)。
✅ 运行时通过 ConfigurableEnvironment 修改配置(有限制)
Spring Boot 允许在应用运行中直接操作 Environment,但需注意:
-
@Value注入的字段不会自动刷新(除非配合@RefreshScope); -
@ConfigurationProperties类需加@RefreshScope或使用@ConfigurationPropertiesRefresh(Spring Boot 2.4+); - 修改后仅对新创建的 Bean 或显式调用
environment.getProperty()生效。
@Component
public class RuntimeConfigUpdater {
private final ConfigurableEnvironment environment;
public RuntimeConfigUpdater(ConfigurableEnvironment environment) {
this.environment = environment;
}
public void setProperty(String key, String value) {
MutablePropertySources sources = environment.getPropertySources();
// 替换或新增:addLast 优先级低,addFirst 优先级高(覆盖原有)
sources.addFirst(new MapPropertySource("runtime", Collections.singletonMap(key, value)));
}
}
调用示例(如通过 HTTP 接口):
@RestController
public class ConfigController {
private final RuntimeConfigUpdater updater;
public ConfigController(RuntimeConfigUpdater updater) {
this.updater = updater;
}
@PostMapping("/config/update")
public String update(@RequestParam String key, @RequestParam String value) {
updater.setProperty(key, value);
return "OK";
}
}
✅ 适用场景:灰度开关、调试参数、临时降级配置
❌ 不适用:已注入@Value的字段值不会变;@ConfigurationProperties对象需手动刷新或重启 Bean。
✅ 结合 @RefreshScope 实现 Bean 级热刷新(推荐组合)
若你希望修改配置后,相关 Bean 自动重新初始化(比如 @Service 中的 @Value 字段更新),需:
- 给目标 Bean 加
@RefreshScope; - 修改
Environment(如上); - 触发刷新(Spring Boot Actuator 的
/actuator/refresh)——但注意:这属于 Spring Cloud 生态功能,需引入spring-cloud-starter和spring-boot-starter-actuator,并开启端点。
# application.yml
management:
endpoints:
web:
exposure:
include: refresh
curl -X POST http://localhost:8080/actuator/refresh
此时带 @RefreshScope 的 Bean 会被销毁重建,重新注入最新配置值。
✅ 小结:不同场景对应方法
-
启动前加载外部配置(如 DB、Consul) →
ApplicationContextInitializer -
运行时临时覆盖某几个 key → 直接操作
ConfigurableEnvironment.getPropertySources() -
希望 Bean 自动响应变更 →
@RefreshScope+ Actuator/refresh - 多实例集群统一配置 → 必须搭配 Spring Cloud Config / Nacos / Apollo 等配置中心
-
修改 server.port、spring.profiles.active 等启动参数 → 只能通过命令行
--server.port=9000或系统属性-Dspring.profiles.active=prod,无法运行时改(嵌入式容器已初始化)
不复杂但容易忽略:所有动态修改都依赖“配置源优先级”机制——后加入的 PropertySource 会覆盖前面同名 key。合理使用 addFirst() 或 addLast() 控制覆盖行为。











