CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Spring Cloud 微服务入门/课时/Cloud Config 配置中心
RawBlame
课时目录10 节

Spring Cloud 微服务入门

  1. 01微服务与 Spring Cloud
  2. 02架构模式与术语
  3. 03服务注册与 Eureka
  4. 04Spring Cloud Gateway
  5. 05Cloud Config 配置中心
  6. 06OpenFeign 服务调用
  7. 07熔断与容错
  8. 08Spring Data 扩展
  9. 09Micrometer 与可观测性
  10. 10综合练习与部署直觉

Cloud Config 配置中心

集中配置、Git 仓库、动态刷新。

30 分钟

Cloud Config 配置中心

这一课你将能做到

  1. 搭起一个 Config Server(本地文件模式和 Git 模式都会配),让 problem-service 启动时自动拉取远程配置
  2. 用 @RefreshScope 实现「改配置不重启」:改一个限流开关,调 refresh 端点立刻生效
  3. 说清配置刷新的底层原理和 spring.config.import 的加载顺序

为什么要学

三个微服务时每人一份 application.yml 还行;十个服务 × dev/test/prod 三环境就是 30 份文件。改一个 Redis 地址要改 10 份再逐个重启,漏一份就是线上事故。配置中心把配置从代码仓库剥离、集中到一处:多环境隔离、按服务命名、支持动态刷新。

Spring Cloud Config 是官方方案:配置存在 Git 仓库(天然有版本历史和审批流),Config Server 对外提供读取,各服务作为 Config Client 启动时拉取。国内 Nacos Config 也是同类方案(带 UI、推送更快),原理相通——学懂 Config,「配置如何集中、如何刷新」这套心智模型直接平移。

先建立图像

┌─────────────────────────────┐
│  Git 仓库 config-repo        │
│   application.yml           │  ← 所有服务共享的默认配置
│   problem-service.yml       │  ← 服务专属配置
│   problem-service-dev.yml   │  ← 服务 + 环境专属配置
└──────────────┬──────────────┘
               │ Server 拉取(可缓存)
┌──────────────▼──────────────┐
│   Config Server :8888        │
└──────────────┬──────────────┘
               │ Client 启动时 HTTP 拉取 /actuator/refresh 时重拉
   ┌───────────┼───────────┐
   ▼           ▼           ▼
 user-svc   problem-svc  judge-svc

Client 端加载优先级(高 → 低):problem-service-dev.yml > problem-service.yml > application-dev.yml > application.yml > 本地 application.yml。远程配置默认覆盖本地同名项。

跟着做

步骤 1:搭建 Config Server

新建模块 config-server,pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.example</groupId>
        <artifactId>cloud-demo</artifactId>
        <version>1.0.0</version>
    </parent>
    <artifactId>config-server</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
    </dependencies>
</project>

启动类:

package com.example.config;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}

本地演示先用 native 模式(直接读本地目录,不依赖 Git),application.yml:

server:
  port: 8888
spring:
  application:
    name: config-server
  profiles:
    active: native
  cloud:
    config:
      server:
        native:
          search-locations: file:///D:/work/config-repo   # Windows 路径;Linux 用 file:///opt/config-repo

步骤 2:准备配置仓库

新建目录 config-repo,放两个文件。

problem-service-dev.yml:

judge:
  daily-limit: 20          # 每日提交上限
  enable-new-engine: false # 判题引擎灰度开关
server:
  port: 8082

application.yml(所有服务共享):

management:
  endpoints:
    web:
      exposure:
        include: health,refresh

启动 Config Server,验证读取:

curl http://localhost:8888/problem-service/dev

返回 JSON 里能看到 propertySources 按「服务+环境 → 服务 → 全局」顺序排列,后面的覆盖前面的。

切 Git 模式只需替换后端配置:

spring:
  profiles:
    active: git
  cloud:
    config:
      server:
        git:
          uri: https://github.com/your-org/config-repo
          default-label: main
          # 私有仓库追加:
          # username: ${GIT_USER}
          # password: ${GIT_TOKEN}

生产用 Git 模式:每次改配置是一次 commit,有历史、可回滚、可审计。

步骤 3:Client 接入

problem-service 加依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>

problem-service 的 application.yml(Boot 3.x / Cloud 2023.x 用 spring.config.import,旧版 bootstrap.yml 已弃用):

spring:
  application:
    name: problem-service
  profiles:
    active: dev
  config:
    import: optional:configserver:http://localhost:8888
  • optional: 表示 Config Server 挂了也能用本地配置启动(演示友好;生产可去掉 optional 强依赖)。
  • Client 会按 {应用名}-{profile}.yml 的规则去 Server 拉取。

写一个读配置的接口验证:

package com.example.problem.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class FeatureController {

    @Value("${judge.daily-limit:0}")
    private int dailyLimit;

    @Value("${judge.enable-new-engine:false}")
    private boolean newEngine;

    @GetMapping("/features")
    public String features() {
        return "dailyLimit=" + dailyLimit + ", newEngine=" + newEngine;
    }
}

访问 http://localhost:8082/features,能看到配置中心下发的值。

步骤 4:动态刷新(不重启)

给 Bean 加 @RefreshScope:

package com.example.problem.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

@Component
@RefreshScope
@ConfigurationProperties(prefix = "judge")
public class JudgeProperties {
    private int dailyLimit;
    private boolean enableNewEngine;

    public int getDailyLimit() { return dailyLimit; }
    public void setDailyLimit(int dailyLimit) { this.dailyLimit = dailyLimit; }
    public boolean isEnableNewEngine() { return enableNewEngine; }
    public void setEnableNewEngine(boolean enableNewEngine) { this.enableNewEngine = enableNewEngine; }
}

修改 config-repo 里的 judge.daily-limit 为 50 并保存(Git 模式下是提交并推送),然后触发刷新:

curl -X POST http://localhost:8082/actuator/refresh

再访问 /features:值已变成 50,服务没有重启。注意 actuator 需要在依赖里(spring-boot-starter-actuator),且 exposure 包含 refresh。

讲清楚要点

  1. 两个角色:Config Server 读后端存储(Git/本地/ SVN)对外提供 HTTP 读取;Config Client 启动时拉取并合并进自己的 Environment。
  2. 命名规则决定拉什么:{application}、{application}-{profile}、{application}/{label}(label 即 Git 分支);最常用的组合是 problem-service-dev.yml。
  3. 刷新原理(面试高频):POST /actuator/refresh → Client 重新从 Server 拉取 Environment → 发布 EnvironmentChangeEvent → @ConfigurationProperties Bean 重新绑定 → @RefreshScope 的 Bean 被销毁,下次使用时懒加载重建,于是拿到新值。
  4. @RefreshScope 是白名单机制:没打这个注解的 Bean(比如普通 @Value 注入的单例)刷新后仍是旧值——这是最容易踩的坑。
  5. 启动期配置刷新不了:数据源连接、端口这类在启动阶段就固定的配置,改了必须重启;适合刷新的是业务开关、阈值、白名单等运行期参数。
  6. Spring Cloud Bus 是广播手段:单实例手动 curl 可以,几十个实例就要用 Bus——向 MQ 发一条刷新事件,所有订阅实例各自触发 refresh,配合 Git webhook 实现「一次提交全集群生效」。

你可能会懵的地方

  • 为什么不直接用环境变量? 十二因子应用确实推荐环境变量,但它只适合少量启动期配置(镜像里不可变);配置中心的价值在「集中 + 多环境 + 动态刷新 + 版本审计」。两者不冲突:启动项用环境变量,业务开关进配置中心。

  • @Value 和 @ConfigurationProperties 哪个配合刷新更好? @ConfigurationProperties + @RefreshScope。@ConfigurationProperties 支持宽松绑定与校验,且 EnvironmentChangeEvent 本身就会触发它重新绑定;@Value 必须连带 RefreshScope 才会更新。

  • Config Server 挂了服务还能启动吗? 用了 optional:configserver: 前缀可以(回退本地配置);生产建议:Client 本地缓存上次拉到的配置(spring.cloud.config.fail-fast 与重试配置),Server 多实例部署在网关后面。

  • 配置里有密码怎么办? Config 支持对称/非对称加密:把 {cipher}密文 存进 Git,Server 启动时配 encrypt key,返回给 Client 前自动解密。也可交给 Vault/Nacos 的加密能力。密码永远不要明文进 Git。

  • Nacos Config 和 Config 怎么选? Nacos:长轮询推送、秒级生效、带控制台、注册配置一体,国内新项目主流;Config:Git 审计流天然强、与官方栈零成本。选型看团队:要 UI 和推送选 Nacos,要 Git 流程选 Config,模型一致不用慌。

错法对照

错法问题正解
Client 写死 http://localhost:8888 进镜像环境迁移即失效configserver:${CONFIG_URL:...} 环境变量注入
改了配置只在 Server 侧改,Client 不动Client 只有启动/refresh 时才拉取改完必须触发 /actuator/refresh 或走 Bus
给数据源 Bean 加 @RefreshScope 期待热更新连接池启动期已固定,刷新无效反而生乱启动期配置接受重启;只热更业务开关
所有配置都堆 application.yml 共享文件服务间互相覆盖,职责不清共享放 application.yml,服务差异放 {服务名}-{profile}.yml
refresh 端点对公网开放任何人可改运行时行为网关不路由 actuator,或加 Spring Security 保护

卡点急救

  1. Client 启动报 Config data resource ... does not exist 或直接失败:去掉了 optional: 但 Server 没起;或 Server 侧 search-locations 路径写错。先用 curl http://localhost:8888/problem-service/dev 验证 Server 是否能返回内容。
  2. refresh 后值没变:①Bean 没加 @RefreshScope;②actuator 没暴露 refresh 端点;③native 模式下文件没保存生效。三处逐一排查,/actuator/refresh 的响应体会列出哪些 key 变了。
  3. 配置文件中文乱码:config-repo 里的 yml 必须是 UTF-8 编码;Windows 下用记事本编辑常被存成 GBK,换 VS Code 并确认右下角编码。

面试常问

  • 配置动态刷新的原理?(必背) ①Client 收到 POST /actuator/refresh → ②重新向 Config Server 拉取配置构造新 Environment → ③发布 EnvironmentChangeEvent,对比前后差异 → ④所有 @ConfigurationProperties Bean 重新绑定 → ⑤@RefreshScope 标注的 Bean 从容器销毁,下次注入时用新 Environment 懒创建 → ⑥普通单例 Bean 不受影响(保持旧值)。追问 Bus 就补「通过 MQ 广播 RefreshRemoteApplicationEvent,避免逐台 curl」。

  • 多个服务共享配置怎么设计? 三层:application.yml 放全局默认(日志格式、actuator 暴露)→ {service}.yml 放服务专属 → {service}-{profile}.yml 放环境差异。优先级由高到低加载,同名键高层覆盖低层。能讲出「为什么密码不放共享层」更好(最小可见性)。

  • bootstrap.yml 和 spring.config.import 的区别? Cloud 2020 前用 bootstrap.yml 在「父上下文」先加载 Config Server 地址再拉配置;2020+ 改为标准 spring.config.import=configserver: 机制,把远程配置纳入 Spring Boot 统一的配置导入流程。新项目一律用 import,见到 bootstrap 意识到是老项目即可。

自测三问

  1. Client 端从配置中心拉取的优先级顺序是什么?
  2. /actuator/refresh 触发后容器里发生了哪几件事?
  3. 为什么 @RefreshScope 之外的 Bean 刷新后还是旧值?

小结一句话

配置中心把配置从代码剥离集中到 Git:Server 统一供读、Client 启动拉取、@RefreshScope 配合 refresh 端点实现不重启的热更新。

延伸

  • Spring Cloud Config 官方文档
  • 下一课:OpenFeign 服务调用——像调本地方法一样调别的服务。
加载本节练习…
← 上一课Spring Cloud Gateway下一课 →OpenFeign 服务调用