Spring Cloud 配置中心原理与实战

🎯 面试题:配置中心是如何实现配置热更新的?

配置中心解决的是「多环境、多实例配置管理」的问题。修改配置不需要重新部署应用,改完配置后应用自动感知并刷新。本题考察分布式配置管理的核心原理。


一、为什么需要配置中心

传统方式的问题:
  改配置 → 改每个实例 → 重启所有实例
  多个环境(dev/test/staging/prod)配置不同 → 维护成本极高

配置中心的作用:
  所有配置集中管理 → 改一处 → 所有实例自动感知
  改配置不需要重启应用(热更新)

二、Apollo 配置中心

架构

┌──────────────────────────────────────────────────┐
│                   Apollo Portal(管理界面)           │
│        新增/修改/回滚配置、发布配置、灰度发布             │
└───────────────────────┬──────────────────────────┘
                        │ HTTP
                        ↓
┌──────────────────────────────────────────────────┐
│              Apollo Config Service(配置读取服务)     │
│          提供配置读取 API、分发配置变更通知             │
└───────────────────────┬──────────────────────────┘
                        │
         ┌──────────────┼──────────────┐
         ↓              ↓              ↓
    ┌─────────┐   ┌─────────┐   ┌─────────┐
    │ App-1   │   │ App-2   │   │ App-3   │
    │ Config  │   │ Config  │   │ Config  │
    │ Client   │   │ Client  │   │ Client  │
    └─────────┘   └─────────┘   └─────────┘

Apollo Meta Server:统一入口(类似 Nginx)
Apollo Admin Service:配置管理的后端(增删改配置)

核心原理

// 1. 客户端启动时拉取所有配置
Config config = Config.getInstance();

// 2. 注册监听器,配置变更时自动回调
config.addChangeListener(changeEvent -> {
    for (String key : changeEvent.changedKeys()) {
        ConfigChange change = changeEvent.getChange(key);
        String newValue = change.getNewValue();
        // 更新内存中的配置
        updateConfig(key, newValue);
    }
});

// 3. 长轮询:客户端每 5 秒拉取一次配置(检测配置变更)
// 如果服务端配置没变,返回 HTTP 304
// 如果配置变了,返回最新配置并触发监听器

Spring Boot 接入

# application.yml
apollo:
  meta: http://apollo-config:8080
  app-id: order-service
  cluster: default
  namespace: application
  bootstrap:
    enabled: true
  config:
    refresh-interval: 5000  # 5秒轮询
// 开启配置热刷新
@RefreshScope
@Configuration
public class AppConfig {
    @Value("${max-connections:100}")
    private int maxConnections;

    @Bean
    public RestTemplate restTemplate() {
        // maxConnections 改变后,这个 Bean 会自动重建
        return new RestTemplateBuilder()
            .rootUri("http://user-service")
            .build();
    }
}

三、Nacos 配置管理

配置模型

Nacos 配置:
  Data ID = ${prefix}.${spring-profile-active}.${file-extension}
  示例:order-service-dev.yaml

Group:配置分组,默认 DEFAULT_GROUP
Namespace:命名空间,隔离不同环境(dev/test/prod)

配置变更推送

// 1. 监听配置变更
@Configuration
public class NacosConfig {
    @NacosConfigurationProperties(dataId = "order-service.yaml", autoRefreshed = true)
    public class OrderProperties {
        @NacosValue("${max-order-per-user:1}")
        private int maxOrderPerUser;
    }
}

// 2. 监听器模式(手动)
@NacosInjected
private ConfigService configService;

@PostConstruct
public void init() {
    configService.addListener(
        "order-service.yaml", "DEFAULT_GROUP",
        new Listener() {
            public Executor getExecutor() { return null; }
            public void receiveConfigInfo(String configInfo) {
                // 配置变更回调
                log.info("配置变更: {}", configInfo);
            }
        }
    );
}

四、配置热刷新原理

长轮询 vs 长连接

方案一:短轮询(效率低)
  客户端每隔 N 秒问服务端:有变化吗?
  服务端:没有变化 → HTTP 304
  问题:响应慢,最多延迟 N 秒,且服务端压力大

方案二:长轮询(推荐)
  客户端问:有变化吗?→ 服务端不立即返回
  如果有变化 → 立即返回最新配置
  如果超时(如 30 秒) → 返回 304,让客户端继续轮询
  优点:服务端无额外压力,客户端及时感知

方案三:长连接(WebSocket/MQ)
  客户端建立长连接,服务端有变化立即推送
  优点:最快感知
  缺点:需要维护长连接,实现复杂

@RefreshScope 原理

// @RefreshScope 注解的实现原理:
// 1. 被标记的 Bean 放入 RefreshScope 的 BeanMap
// 2. 配置变更时,触发 ContextRefresher
// 3. RefreshScope 创建一个新的 BeanFactory
// 4. 从旧 BeanFactory 复制非 @Value 的 Bean
// 5. 新 BeanFactory 创建所有 @RefreshScope 的新 Bean
// 6. 新 Bean 使用最新配置值

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Scope("refresh")
@Documented
public @interface RefreshScope {
}

// 实际触发刷新:
// 1. Nacos/Apollo 监听器收到配置变更通知
// 2. 发送 POST /actuator/refresh
// 3. ContextRefresher.refresh() 执行上述流程

五、高频面试题

Q1: 配置中心如何实现热更新?

核心是长轮询 + @RefreshScope。配置中心(如 Nacos/Apollo)维护配置版本号,客户端每隔 30 秒轮询拉取配置,如果配置有变化则立即返回最新值。客户端收到变更后,通过 @RefreshScope 重新创建 Bean,新 Bean 使用最新配置。也可以用 Spring Cloud Bus(基于 MQ)实现配置变更广播,触发所有实例同时刷新。

Q2: 为什么需要配置中心?

三个原因:① 多环境管理:dev/test/staging/prod 配置不同,传统方式需要维护多套配置文件;② 配置变更不需要重启:配置中心热更新,改完配置应用自动感知;③ 集中管理:所有配置在一处管理,支持灰度发布、回滚、审计。大型分布式系统可能有几十个微服务,配置中心是必需的。

Q3: 配置变更推送用什么机制?

两种主要机制:① 长轮询(Nacos/Apollo):客户端保持 HTTP 连接,服务端有变更立即返回,无变更则超时后返回 304;② 长连接/消息推送:服务端维护 WebSocket 或 TCP 连接,有变更主动推送。Nacos 默认用长轮询,Apollo 早期用轮询,后来也改成长轮询。Spring Cloud Bus 用 MQ 广播刷新事件,实现集群内所有实例同时感知。