前言

拼单系统里有些配置变化很快,比如活动开关、接口降级开关、试算超时时间、库存保护阈值、回调通道选择。如果每次调整都要发版,运营节奏会很慢,也容易因为临时改代码引入风险。

我在简历里把这块写成 Redis 发布/订阅实现动态配置中心,也就是 DCC。当前仓库里基础配置还主要放在 application.yml,但这篇记录的是我设计 DCC 时的落地思路:通过注解标记可刷新字段,Redis Pub/Sub 推送变更,监听器收到后用反射更新内存值。

DCC要解决的问题

DCC 不需要一开始做成 Nacos 或 Apollo 那么完整。对这个项目来说,第一阶段只要解决三个问题:配置能集中存储,变更能秒级通知应用,业务代码读取的是最新值。

比如试算接口的超时时间默认 300ms,高峰期 Redis 抖动时可以临时调到 500ms;活动开关发现异常时可以立刻关闭;回调通道从 HTTP 切到 MQ,也不希望重启服务。

注解标记字段

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DccValue {
    String key();
    String defaultValue() default "";
}

@Component
public class TrialConfig {
    @DccValue(key = "trial.query.timeout.ms", defaultValue = "300")
    private volatile long trialTimeoutMs;

    @DccValue(key = "trial.degrade.enable", defaultValue = "false")
    private volatile boolean degradeEnable;
}

字段用 volatile 是为了保证刷新后其他线程能尽快看到新值。注解里放 key 和默认值,启动时扫描 Bean,把字段和配置 key 建立映射。这样业务代码可以继续注入 TrialConfig,不需要每次都主动查 Redis。

Redis发布订阅

配置变更时,后台或脚本先写 Redis Hash,再向某个 channel 发布 key。应用订阅 channel,收到 key 后重新读取配置并更新字段。这个模式很轻,适合单体或中小规模服务。

// 配置后台伪代码
redisTemplate.opsForHash().put("dcc:config", key, value);
redisTemplate.convertAndSend("dcc:changed", key);

// 应用监听伪代码
public void onMessage(String key) {
    String value = redisTemplate.opsForHash().get("dcc:config", key).toString();
    dccRegistry.refresh(key, value);
}

发布订阅只负责通知,不负责持久化,所以真实值仍然要存在 Redis Hash 或数据库里。否则应用重启后就不知道当前配置是什么。

配置刷新

public void refresh(String key, String value) {
    List<FieldRef> refs = fieldIndex.get(key);
    if (refs == null) return;

    for (FieldRef ref : refs) {
        Object converted = convert(value, ref.field().getType());
        ReflectionUtils.makeAccessible(ref.field());
        ReflectionUtils.setField(ref.field(), ref.bean(), converted);
        log.info("dcc refresh key={} value={}", key, value);
    }
}

反射更新字段时要特别注意类型转换和异常处理。配置值从 Redis 读出来都是字符串,落到字段时可能是 boolean、int、long、BigDecimal。转换失败不能把旧值覆盖掉,应该保留旧值并报警。

小结

DCC 的目标不是替代成熟配置中心,而是在拼单系统里解决快速开关和运行时参数调整问题。注解负责声明,Redis Hash 负责存储,Pub/Sub 负责通知,反射负责刷新。做到这一步,简历里“配置变更时秒级热更新、无感配置下发”的描述就有了具体实现路径。