专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

SpringBoot动态配置修改全攻略:实战12种无重启改配置方案

SpringBoot 动态改配置?我有九招,谁用谁管用!

你说现在这开发日子,真是一天比一天难。做功能吧,刚写完,产品一句话:“这个限流数你别写死啊,要能动态改~”,我当时差点直接摔键盘。
你写代码的时候,他跟你说“这个参数可控就行”,上线后就变成了“我们运营那边每天要调几次,要实时生效,要后台改,不准重启~”

???你咋不早说?

我以前也怨,后来想明白了:怨没用,还是得想招儿解决,哥这 20 年开发下来,没吃过猪肉也看过猪跑,配置这种事——要稳,要灵活,还得抗操!

所以咱不废话,直接上货,整了 12 种我亲测能用的SpringBoot 动态修改配置方法,从最轻量的 @Value 到最重型的 Apollo/Nacos,从“土轮询”到“监听器黑科技”,哪个项目能用我都标明白咧!

不是堆概念,不是拷贝文档,是哥在线上服务器前一边抽烟一边改配置总结出来的真招儿。
会了这 12 套,谁敢跟你说“SpringBoot 配置写死了不能改”,你就直接甩给他:来,我改给你看!

1、@Value 不是废物,只是你用得太死

这玩意儿本来吧,用起来忒顺手,写个

@Value("${timeout:30}")

配置一改,值就跟着走……理想是挺丰满,现实呢?你改完配置,值一点不带变的,得重启;你重启吧,线上可不能断人业务,那就等着背锅吧。

我干脆直接写个环境监听器,谁改配置我就现场拿新值硬灌回去。

@Component
public class TimeoutConfigListener implements ApplicationListener<EnvironmentChangeEvent> {

    @Value("${timeout:30}")
    private String timeout;

    @Override
    public void onApplicationEvent(EnvironmentChangeEvent event) {
        if (event.getKeys().contains("timeout")) {
            // 拿最新值灌进来
            String newVal = ApplicationContextProvider.getContext()
                               .getEnvironment()
                               .getProperty("timeout");
            timeout = newVal;
            System.out.println("超时时间改咧:" + timeout);
        }
    }
}

再整一个 ApplicationContextProvider 搭着用,不然你拿不到环境。

@Component
public class ApplicationContextProvider implements ApplicationContextAware {

    private static ApplicationContext ctx;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        ctx = applicationContext;
    }

    public static ApplicationContext getContext() {
        return ctx;
    }
}

这招儿不优雅不高级,但特他娘的实用,你 yml 配上个 config server,都不如这玩意儿来得直接,线下调试也不费劲,真香!

2、整点 Nacos,热更新你就靠它吃饭

Nacos 这个东西吧,用的人多了,也不稀奇了,但我还是得唠叨一嘴。你要是配得好,配合 Spring Cloud,值一改,Bean 一刷新,整个服务就跟打了鸡血一样,自动变,毫不费劲。

@RefreshScope
@RestController
public class BizController {

    @Value("${biz.feature.switch:false}")
    private boolean featureSwitch;

    @GetMapping("/feature/status")
    public String checkFeature() {
        return "当前功能开关状态:" + featureSwitch;
    }
}

咋样?改配置文件直接生效,但条件是你得让 Spring Cloud 顶着干,bootstrap.yml 要整明白:

spring:
  application:
    name: config-demo
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
        file-extension: yaml

项目一跑起来,后台你在 Nacos 改改值,前台直接拿到,跟魔术似的。
唯一麻烦点儿是,依赖一堆,配置得小心点,不然动不动就连不上,急得脑壳冒汗。

3、Apollo,大厂那味儿就是稳

当年我做政务项目的时候,Apollo 是项目组点名要用的。为啥?稳定!可视化!还能灰度配置!你说一个配置能玩出花儿来,也就 Apollo 了。

@RestController
public class ApolloController {

    @ApolloConfig
    private Config config;

    @GetMapping("/current/env")
    public String getEnv() {
        String env = config.getProperty("app.env", "dev");
        return "当前环境是:" + env;
    }
}

注意啊,这里面不是啥 @Value,而是config.getProperty()去取实时值,Apollo 不走 Spring 原生那一套缓存机制,你改完后台立即生效,干就完了。

而且这玩意儿还能搞发布审核通知灰度开关,那感觉就像玩配置的淘宝后台一样,点点点就全改完。

4、动态切换数据源,听我一句劝,别手抖写死了!

这个事儿我是真有体会,当初我们项目得接三个库,配置写三个 yml 是能整,可问题是一个用户查的是A库,另一个要连B库,你咋办?重启切库?你项目等得起,客户可等不起!

于是我给它整了个自定义 DataSource,再配个ThreadLocal动态换。

核心是这仨玩意:

  1. 多数据源注册
  2. AbstractRoutingDataSource 重写
  3. 接口前加拦截,自己决定用哪个
public class DynamicDataSourceContextHolder {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    public static void setDataSource(String key) {
        contextHolder.set(key);
    }

    public static String getDataSource() {
        return contextHolder.get();
    }

    public static void clearDataSource() {
        contextHolder.remove();
    }
}
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getDataSource();
    }
}

用法也简单,你 controller 里加一行:

DynamicDataSourceContextHolder.setDataSource("tenantA");
// 然后你该咋查咋查

查完别忘清:

DynamicDataSourceContextHolder.clearDataSource();

这一套搞下来,你前台想调哪个库,后端就给你切上哪个,调度员附体,稳得一批
当然你配置那块得提前准备好每个库,别到时候报个死库错,吓尿。

5、运行时动态修改 Bean 属性?别当 Spring 容器摆设了

你是不是也有这种场景,某个 service 里的参数,平时都写死了,结果临上线前项目经理一句话:“给我调成20,不要重启~”

那你还用注入?直接暴力反射或者从上下文里拿对象,改属性,生效秒见效!

@Service
public class BizService {

    private int retryCount = 3;

    public void doSomething() {
        System.out.println("当前重试次数:" + retryCount);
        // 执行逻辑
    }

    public void setRetryCount(int retryCount) {
        this.retryCount = retryCount;
    }
}

然后你页面调用接口改这个值:

@Autowired
private ApplicationContext ctx;

@PostMapping("/set-retry")
public String setRetry(@RequestParam int count) {
    BizService bean = ctx.getBean(BizService.class);
    bean.setRetryCount(count);
    return "已设置重试次数为:" + count;
}

看着就 low ?low 但好使,谁用谁知道,特别是那种跑批逻辑的 service,要改时间、改间隔,全靠它!

6、用缓存模拟配置?Map 里一写,说改就改!

有时候你项目没搞 Nacos、Apollo,又不想用那么重的监听器咋办?那你整一份缓存 Map,配合数据库或者 Redis,读取配置数据,页面改完后直接刷内存,简直不要太轻便!

@Component
public class InMemoryConfig {

    private final Map<String, String> configMap = new ConcurrentHashMap<>();

    public String get(String key) {
        return configMap.getOrDefault(key, "");
    }

    public void set(String key, String val) {
        configMap.put(key, val);
    }
}

然后你 controller 随便整俩接口:

@Autowired
private InMemoryConfig config;

@PostMapping("/update-config")
public String update(@RequestParam String key, @RequestParam String value) {
    config.set(key, value);
    return "更新成功";
}

@GetMapping("/get-config")
public String get(@RequestParam String key) {
    return config.get(key);
}

你随便丢个管理后台出来,搞个表单,一点就改,后端 Map 直接改值,全项目调用的地方同步拿的就是更新后的值。

适合啥项目?适合那种小公司内部项目+启动慢但改动频繁的系统。啥 Nacos、啥 Apollo?用不起或者懒得接,Map 直接干!

7、Spring Cloud Config:远程配置 + 实时刷新,配置一多就靠它

你要是做分布式、微服务那种,配置动不动几十个服务一套,那用本地application.yml基本等于找死。
Spring Cloud Config 就是干这活儿的!一套 Git 上托管 yml,所有服务拉最新,还支持@RefreshScope自动刷新,谁用谁真香。

先整服务端:
一个专门跑 Config 的 Spring Boot 服务,配置 Git 地址就行:

server:
  port: 8888

spring:
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/your-team/config-repo.git

客户端加这两口子:

spring:
  application:
    name: your-app
  cloud:
    config:
      uri: http://localhost:8888

再加个神技:

@RefreshScope
@RestController
public class ConfigClientController {

    @Value("${biz.name:default}")
    private String bizName;

    @GetMapping("/get-biz")
    public String biz() {
        return "当前业务名:" + bizName;
    }
}

一改 Git 配置,调用/actuator/refresh就能刷新配置。

你说这香不香?不用重启,不用手改配置文件,不用进服务器找 yml,运维都给你点赞!

8、定时拉配置:不依赖框架,就靠你自己瞎鸡儿轮询

这方法我给它起名叫:“笨法里的王者”

有时候你不能接中心、不能用动态注解,那你咋办?
写个定时任务,每 5 秒、10 秒去 Redis、数据库查一遍配置,拉下来扔内存 Map 里,效果一样能动态生效。

@Component
public class ConfigPuller {

    private final Map<String, String> localCache = new ConcurrentHashMap<>();

    @Scheduled(fixedRate = 10000)
    public void refreshConfig() {
        // 模拟从 Redis 查
        String val = redisTemplate.opsForValue().get("sys.timeout");
        if (val != null) {
            localCache.put("sys.timeout", val);
            System.out.println("刷新配置,当前timeout:" + val);
        }
    }

    public String get(String key) {
        return localCache.getOrDefault(key, "");
    }
}

不用接中心,不用注解,就是纯靠轮询,越土越稳。

特别适合那种传统系统,不用改结构,也能搞动态配置,运维不支持搞 Apollo?自己就地开个 Redis 做中心,照样能跑!

9、基于事件的配置刷新机制,配置改了自动通知各模块

这招是骚气中带着灵气,我项目里配置更新之后要通知多个模块重新初始化,那咋办?
用事件!

public class ConfigUpdateEvent extends ApplicationEvent {
    private final String key;
    private final String value;

    public ConfigUpdateEvent(Object source, String key, String value) {
        super(source);
        this.key = key;
        this.value = value;
    }

    // get方法略
}

然后谁感兴趣谁就监听:

@Component
public class BizModule implements ApplicationListener<ConfigUpdateEvent> {

    @Override
    public void onApplicationEvent(ConfigUpdateEvent event) {
        if ("biz.switch".equals(event.getKey())) {
            System.out.println("收到配置更新事件,biz.switch 改成了:" + event.getValue());
            // 你想干啥干啥,比如切换开关
        }
    }
}

你 controller 一改配置,发布事件:

@Autowired
private ApplicationEventPublisher publisher;

@PostMapping("/update")
public String update(@RequestParam String key, @RequestParam String val) {
    // 更新你本地缓存后
    publisher.publishEvent(new ConfigUpdateEvent(this, key, val));
    return "配置发布成功";
}

这叫啥?这叫“模块级协作”,自己通知自己模块更新,优雅得不行
比起你在代码里 if else 改值,不知道高到哪里去咧!

10、利用 Spring 的 Environment 动态修改配置(Hack版)

这招说实话有点“擦边球”操作,官方没推荐,但实战真用得上。我做活动平台时就干过——一个 Redis 配置临时改掉,结果重启项目又还原,最后我直接怼进 Spring 的环境变量里。

@Autowired
private ConfigurableEnvironment environment;

public void updateProperty(String key, String value) {
    MutablePropertySources propSources = environment.getPropertySources();
    // 找到系统环境变量那层,把值给 override 了
    Map<String, Object> map = new HashMap<>();
    map.put(key, value);
    propSources.addFirst(new MapPropertySource("customOverride", map));
}

直接强塞配置进去,强插队的思路
注意:你这层如果没加在前面,可能还被别的源给覆盖了,一定要 .addFirst()

这招唯一问题就是重启就没了,适合那种“运行中救火”的临时操作,真香!

11、写个 @ConfigurationProperties + 外部改 Bean 值

这事儿很多人都搞不明白:为啥 @Value 热不起来?为啥 @ConfigurationProperties 更好?
我告诉你,你看下面这段配置类,只要你搞了 @RefreshScope + 外部动态 set,你就能随便控制值——

@Component
@ConfigurationProperties(prefix = "biz.config")
@RefreshScope
public class BizProperties {
    private int threadCount;
    private boolean enable;

    // getter/setter...
}

然后呢?你 controller 里直接注入这 Bean,动态 set 值:

@Autowired
private BizProperties props;

@PostMapping("/set-thread")
public String update(@RequestParam int count) {
    props.setThreadCount(count);
    return "线程数改成:" + count;
}

很多人以为@ConfigurationProperties是只能读 yml,其实只要你能控制 Bean 实例,那它就能动态改。
别被文档骗咧,这玩意儿好用得很!

12、Zookeeper + 本地监听器,改配置还送通知

有段时间我跟一家做金融交易的合作,非要用 ZK 做中心化配置,Apollo 和 Nacos都嫌弃,我们就这么干的:

Zookeeper 存 key-value,节点数据一改,本地监听器自动收通知。

zkClient.subscribeDataChanges("/config/timeout", new IZkDataListener() {
    @Override
    public void handleDataChange(String dataPath, Object data) {
        System.out.println("配置改了:" + dataPath + " = " + data);
        // 更新你本地缓存逻辑
    }

    @Override
    public void handleDataDeleted(String dataPath) {
        System.out.println("配置被删了:" + dataPath);
    }
});

一改 ZK 节点,服务端立马就感知。
你要觉得 ZK 就只能做注册中心,那你是真没用过“它监听数据变化的骚操作”!

这招适合啥?适合那种内网复杂、不能开放外部 API、但配置得共享的场景。
不重启、不重拉、不定时刷,改一次全系统感知,贼刺激!

结尾:别光抄代码,记住这些思路才是关键!

行了哥们,12招全抖完了,咱们收个尾。

你看啊,这12套骚操作,其实也能分门别类整理下思路:

分类 技术方案 特点
🧱 本地轻量玩法 @Value+监听器、内存Map缓存、Env注入、配置类手改 轻便、适合小项目
☁️ 中心化配置 Nacos、Apollo、Spring Cloud Config、Zookeeper监听 适合多服务协同、大厂味十足
🔄 极限骚操作 动态换数据源、运行时改Bean属性、事件发布更新、定时轮询拉配置 没有框架依赖,手动拉扯、灵活暴力

说到底——

配置这玩意儿,说简单也简单,说复杂也能复杂到飞起。
你项目小,选本地 Map、监听器自己玩就够了;
你项目大,要扛流量,要统一治理,那你 Apollo、Nacos 不用都对不起自己;
你需求急、客户催、不能上线,那你 runtime 直接干内存那一套,谁拦你谁背锅。

我写这些不是装、也不是教你啥“最佳实践”那套官方鬼话,
我就是想让你真遇到问题的时候,有得用,有得选,不用一脸懵逼盯着yml改完重启再挨骂。

未经允许不得转载:搜云库 » SpringBoot动态配置修改全攻略:实战12种无重启改配置方案

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们