面试之springboot的动态改配置

面试时候,基础的知识还是要好好整理的,今天有一个兄弟就跟我说他遇到了一个问SB动态改配置的方法有哪些,我整理了下,大概就这些:

在开发过程中,配置的动态修改几乎是每个项目都会遇到的需求。有时候,产品会在上线后要求动态调整参数,而不能重启服务。为了应对这些需求,我总结了 12 种 SpringBoot 动态改配置的方法,从简单的本地实现到复杂的中心化配置,总有一种适合你的项目。

1. @Value + 环境监听器:简单实用的本地方案

@Value 注解虽然简单,但默认修改配置后需要重启服务。通过结合环境监听器,可以实现动态修改.

@Component
public class TimeoutConfigListener implements ApplicationListener {
    @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;
    }
}

这种方法简单直接,适合小型项目。

2. Nacos:强大的中心化配置管理

Nacos 是一个常用的中心化配置管理工具,结合 Spring Cloud 可以轻松实现配置的动态刷新.

@RefreshScope
@RestController
public class BizController {
    @Value("${biz.feature.switch:false}")
    private boolean featureSwitch;

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

bootstrap.yml 中配置 Nacos:

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

修改 Nacos 中的配置后,服务会自动刷新,无需重启。

3. 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;
    }
}

Apollo 不依赖 Spring 的缓存机制,修改配置后会立即生效。

4. 动态切换数据源

在多数据源场景下,可以通过 AbstractRoutingDataSourceThreadLocal 动态切换数据源。

核心代码如下:

public class DynamicDataSourceContextHolder {
    private static final ThreadLocal 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 容器中获取 Bean,可以直接修改其属性.

@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;
}

这种方法适合需要动态调整服务参数的场景。

6. 使用内存 Map 模拟配置

通过内存 Map 存储配置,结合数据库或 Redis,可以快速实现动态配置.

@Component
public class InMemoryConfig {
    private final Map configMap = new ConcurrentHashMap<>();

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

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

提供接口操作配置:

@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);
}

这种方法适合小型项目,无需复杂的配置中心。

7. Spring Cloud Config:分布式配置管理

Spring Cloud Config 是一个强大的分布式配置管理工具,支持 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 动态刷新:

@RefreshScope
@RestController
public class ConfigClientController {
    @Value("${biz.name:default}")
    private String bizName;

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

修改 Git 配置后,调用 /actuator/refresh 即可刷新配置。

8. 定时拉取配置:轮询机制

通过定时任务定期从 Redis 或数据库拉取配置,更新到内存中.

@Component
public class ConfigPuller {
    private final Map localCache = new ConcurrentHashMap<>();

    @Scheduled(fixedRate = 10000)
    public void refreshConfig() {
        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, "");
    }
}

这种方法简单直接,适合无法使用配置中心的场景。

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 {
    @Override
    public void onApplicationEvent(ConfigUpdateEvent event) {
        if ("biz.switch".equals(event.getKey())) {
            System.out.println("收到配置更新事件,biz.switch 改成了:" + event.getValue());
        }
    }
}

发布事件:

@Autowired
private ApplicationEventPublisher publisher;

@PostMapping("/update")
public String update(@RequestParam String key, @RequestParam String val) {
    publisher.publishEvent(new ConfigUpdateEvent(this, key, val));
    return "配置发布成功";
}

这种方法适合需要多模块协作的场景。

10. 利用 Spring 的 Environment 动态修改配置

通过操作 Spring 的 Environment,可以直接修改配置.

@Autowired
private ConfigurableEnvironment environment;

public void updateProperty(String key, String value) {
    MutablePropertySources propSources = environment.getPropertySources();
    Map map = new HashMap<>();
    map.put(key, value);
    propSources.addFirst(new MapPropertySource("customOverride", map));
}

这种方法适合临时修改配置的场景,重启后会失效。

11. @ConfigurationProperties + 动态修改

通过 @ConfigurationProperties@RefreshScope,可以动态修改配置类的属性。

配置类:

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

    // getter/setter...
}

动态修改:

@Autowired
private BizProperties props;

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

整体来说,大致就这几种可以动态修改springboot的值。
更多精彩,请移步 :codingba 或识别如下二维码,更多咨询等着你。

面试之springboot的动态改配置_第1张图片

你可能感兴趣的:(Java,Java,Server,spring,boot,面试,java)