Appearance
Config 详解:不止是配置中心
Spring Cloud Config 是 Spring Cloud 官方提供的配置管理组件。但它不只是"配置中心"——它是一套完整的配置治理方案,涵盖了配置的存储、版本管理、动态刷新、加密保护、广播通知等多个能力。
一、Config 不只是配置中心
很多人把 Config 简单理解成"把配置文件从本地搬到 Git 仓库",但这个理解过于片面。Config 实际提供的是一套完整的配置治理能力:
┌─────────────────────────────────────────────┐
│ Spring Cloud Config │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 集中管理 │ │ 动态刷新 │ │ 版本管理 │ │
│ │ 统一存储 │ │ 不重启生效│ │ Git 追溯 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 环境隔离 │ │ 加密保护 │ │ 广播通知 │ │
│ │ dev/test/ │ │ 敏感信息 │ │ 一键刷新 │ │
│ │ prod │ │ 密文存储 │ │ 全集群 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ 高可用 │ │ 灰度发布 │ │
│ │ 启动快失败│ │ 按标签推送│ │
│ │ 自动重试 │ │ 配置 │ │
│ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────┘| 能力 | 说明 | 实现方式 |
|---|---|---|
| 集中管理 | 所有服务的配置统一存储在 Git/SVN/Native | Config Server 拉取配置源 |
| 动态刷新 | 修改配置后不用重启服务即可生效 | @RefreshScope + POST /actuator/refresh |
| 版本管理 | 配置变更历史可追溯、可回滚 | Git 天然版本控制,查看 commit log |
| 环境隔离 | dev/test/prod 配置隔离,互不影响 | 文件名规则:{application}-{profile}.yml |
| 加密保护 | 数据库密码等敏感信息密文存储 | {cipher} 前缀 + 对称/非对称加密 |
| 广播通知 | 一次刷新,所有实例同时生效 | Config + Bus + MQ 广播 |
| 高可用 | 配置中心不可用时服务能启动 | fail-fast + retry 机制 |
| 灰度发布 | 配置按标签推送给指定实例 | 4.0+ 支持 spring.cloud.config.label |
一句话:Config 解决的是"配置的治理问题",而不仅仅是"配置的存储问题"。
二、为什么需要配置中心?
2.1 没有配置中心时的痛点
application.yml 散落在每个服务里:
order-service/application.yml → 数据库连接、限流阈值、开关配置
user-service/application.yml → 数据库连接、Redis 地址、开关配置
inventory-service/application.yml → 数据库连接、MQ 地址、开关配置
问题:
1. 配置分散:修改一个配置要改 N 个服务,且需要重新部署
2. 环境混乱:dev/test/prod 配置混在一起,容易出错
3. 无法追溯:谁改了什么配置?什么时间改的?没有记录
4. 安全风险:敏感信息(密码/密钥)明文存储在代码仓库2.2 有了配置中心之后
┌──────────────────────────────────────────────────────────────────┐
│ Spring Cloud Config Server │
│ │
│ Git 仓库 / 本地文件系统(配置源) │
│ ├── application.yml ← 公共配置 │
│ ├── order-service.yml ← 订单服务配置 │
│ ├── order-service-dev.yml ← 订单服务开发环境 │
│ └── order-service-prod.yml ← 订单服务生产环境 │
│ │
│ 所有服务启动时向 Config Server 拉取配置,统一管理 │
└──────────────────────────────────────────────────────────────────┘
↑ ↑ ↑
order-service user-service inventory-service三、核心架构
┌──────────────────────────────────────────────────────────────────┐
│ Config 架构图 │
│ │
│ ┌──────────────┐ │
│ │ Git 仓库 │ ← 配置文件存储(或 SVN、本地文件、Vault) │
│ │ (配置源) │ │
│ └──────┬───────┘ │
│ │ 拉取配置 │
│ ▼ │
│ ┌──────────────────┐ │
│ │ Config Server │ ← 配置服务端,提供 REST API │
│ │ (配置中心服务) │ 端点:/{application}/{profile}[/{label}] │
│ └────────┬─────────┘ │
│ │ 提供配置 │
│ ▼ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Config Client │ │ Config Client │ │
│ │ (order-service) │ │ (user-service) │ │
│ │ │ │ │ │
│ │ 启动时拉取配置 │ │ 启动时拉取配置 │ │
│ │ /actuator/refresh│ │ /actuator/refresh│ │
│ └──────────────────┘ └──────────────────┘ │
│ │
│ 配置刷新流程: │
│ Git 变更 → Config Server → Bus 广播 → Client refresh │
└──────────────────────────────────────────────────────────────────┘四、Config Server 服务端
4.1 依赖
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>4.2 启动类
java
@SpringBootApplication
@EnableConfigServer // 开启配置中心
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}4.3 配置(Git 后端,推荐)
yaml
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://github.com/team/config-repo # Git 仓库地址
search-paths: config # 搜索路径
default-label: main # 默认分支
username: your-username # 私有仓库需要
password: your-password
# 本地缓存(避免 Git 不可用时服务无法启动)
basedir: /tmp/config-repo
clone-on-start: true # 启动时 clone
force-pull: true # 强制拉取最新
refresh-rate: 30 # 刷新间隔(秒)
server:
port: 88884.4 配置(Native 本地文件,适合简单场景)
yaml
spring:
profiles:
active: native
cloud:
config:
server:
native:
search-locations: file:///D:/config-repo # 本地文件路径4.5 访问规则
Config Server 提供 REST API 来获取配置,URL 格式为:
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
示例:
http://localhost:8888/order-service/dev → 返回 order-service-dev.yml
http://localhost:8888/order-service/dev/main → 返回 main 分支的配置
http://localhost:8888/order-service-prod.yml → 返回 order-service-prod.yml五、Config Client 客户端
5.1 依赖
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>5.2 配置(bootstrap.yml)
yaml
# bootstrap.yml 优先级高于 application.yml,用于引导配置
spring:
application:
name: order-service
cloud:
config:
uri: http://localhost:8888 # Config Server 地址
profile: dev # 环境
label: main # 分支
fail-fast: true # 连接失败时快速失败
retry:
initial-interval: 1000 # 重试间隔
max-attempts: 6 # 最大重试次数
multiplier: 1.5 # 间隔倍数
# 暴露 refresh 端点
management:
endpoints:
web:
exposure:
include: refresh5.3 配置热刷新
java
@RestController
@RefreshScope // 标记为可刷新,配置变更时重新初始化 Bean
public class OrderController {
@Value("${order.limit:100}")
private int limit;
@GetMapping("/limit")
public String getLimit() {
return "当前限流阈值:" + limit;
}
}刷新方式:
bash
# 方式一:手动调用(单服务)
curl -X POST http://localhost:8080/actuator/refresh
# 方式二:Bus 批量刷新(推荐,见 Bus 章节)
curl -X POST http://config-server:8888/actuator/busrefresh六、配置优先级
Spring Cloud Config 配置加载顺序(优先级从高到低):
1. 命令行参数 --spring.profiles.active=prod
2. 系统环境变量 JAVA_HOME
3. application-{profile}.yml 远程仓库(Config Server)
4. application.yml 远程仓库(Config Server)
5. application-{profile}.yml 本地(classpath)
6. application.yml 本地(classpath)
7. @PropertySource 注解引入远程配置优先级高于本地配置,这是 Config 的默认行为。可通过
spring.cloud.config.override-none=true修改。
七、配置加密
yaml
# Config Server 端配置加密密钥
encrypt:
key: my-secret-key
# 加密配置值
# POST http://localhost:8888/encrypt Body: mypassword
# 返回: {cipher}xxxxx
# 在配置文件中使用加密值
spring:
datasource:
password: '{cipher}xxxxx' # Config Server 自动解密八、Config vs Nacos:不是简单的对等关系
8.1 Config 是对标 Nacos 吗?
不完全对等。 Nacos 在功能上是 Config 的"超集":
┌─────────────────────────────────────────────────────────────────┐
│ Nacos 是什么? │
│ │
│ ┌──────────────────────┐ ┌──────────────────────┐ │
│ │ 服务注册与发现 │ │ 配置管理 │ │
│ │ (对等 Eureka/Consul) │ │ (对等 Config) │ │
│ │ │ │ │ │
│ │ - 服务注册 │ │ - 配置存储 │ │
│ │ - 健康检查 │ │ - 动态刷新(自动推送) │ │
│ │ - 元数据管理 │ │ - 历史版本 │ │
│ │ - 权重路由 │ │ - 灰度发布 │ │
│ │ - 保护阈值 │ │ - 命名空间/分组 │ │
│ └──────────────────────┘ └──────────────────────┘ │
│ │
│ Nacos = 服务发现(Eureka) + 配置中心(Config) + Web 控制台 │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Spring Cloud Config 是什么? │
│ │
│ ┌──────────────────────┐ │
│ │ 配置管理 │ │
│ │ (只管配置) │ │
│ │ │ │
│ │ - 配置存储(Git) │ │
│ │ - 动态刷新(手动/Bus) │ │
│ │ - 版本管理(Git) │ │
│ │ - 加密保护 │ │
│ └──────────────────────┘ │
│ │
│ Config = 只做配置管理,服务发现需要 Eureka/Consul 配合 │
└─────────────────────────────────────────────────────────────────┘结论:Nacos 相当于 Config + Eureka 二合一,还带 Web 控制台。Config 只做配置管理,服务发现需要另外的组件。
8.2 详细对比
| 维度 | Spring Cloud Config | Nacos |
|---|---|---|
| 定位 | 纯配置管理 | 服务发现 + 配置管理 |
| 配置存储 | Git / SVN / 本地文件 | 内置存储(MySQL / Derby) |
| 配置刷新 | 手动 POST /actuator/refresh + Bus 广播 | 自动推送,秒级生效 |
| 服务发现 | 无,需配合 Eureka、Consul、Zookeeper | 内置,无需额外组件 |
| Web 控制台 | 无 | 有,可视化管理 |
| 版本管理 | 依赖 Git 的 commit 历史 | 内置历史版本,控制台直接查看 |
| 灰度发布 | 通过 Git 分支间接实现 | 内置,按标签/IP 灰度 |
| 命名空间 | 无,通过 profile 区分环境 | 内置 namespace,多环境隔离 |
| 分组 | 无 | 内置 group,按业务分组 |
| 加密 | 内置对称/非对称加密 | 不内置,需应用层自行加密 |
| 高可用 | Config Server 集群 + Git 高可用 | Nacos 集群(内置 Raft 协议) |
| 运维成本 | 需要维护 Git 仓库 + Config Server + Bus(MQ) | 只维护 Nacos 集群 |
| 学习成本 | 中(需理解 Git + Bus 联动) | 低(开箱即用) |
| 生态归属 | Spring Cloud 官方 | Spring Cloud Alibaba |
8.3 核心差异:配置刷新方式
这是两者最大的体验差异:
Config 刷新方式(手动):
开发者修改 Git 配置 → git push
→ POST /actuator/busrefresh(手动触发)
→ Bus 通过 MQ 广播给所有实例
→ 各实例重新加载配置
Nacos 刷新方式(自动):
开发者在 Nacos 控制台修改配置 → 点击发布
→ Nacos 自动推送通知给所有订阅的实例
→ 各实例 @RefreshScope 的 Bean 自动刷新Config 是"拉"模式(需手动触发),Nacos 是"推"模式(自动推送)。 这是 Nacos 作为配置中心最大的体验优势。
8.4 两者能一起使用吗?
可以,但通常没必要。 同时使用 Config 和 Nacos 来管理配置属于"重复造轮子"。
同时使用 Config + Nacos 的问题:
优先级冲突:同一个配置项,Config 和 Nacos 谁说了算?
维护成本:两个地方管理配置,改一个配置要确认两边是否一致
排查困难:配置出问题时,不知道是哪个源头的问题
架构冗余:引入了不必要的复杂度唯一的例外场景: 配置加密需求
Config 内置加密/解密能力({cipher} 前缀),Nacos 没有。
如果你的配置中有大量敏感信息需要加密,可以:
┌──────────────┐ ┌──────────────┐
│ Nacos │ │ Config │
│ 普通配置 │ │ 加密配置 │
│ (开关/阈值) │ │ (密码/密钥) │
└──────────────┘ └──────────────┘
但更好的做法是:用 Vault 管理敏感配置,Nacos 管理普通配置。
或者直接用 Nacos + 应用层自行加密(如 Jasypt)。8.5 用了 Nacos 还有必要用 Config 吗?
绝大多数场景:不需要。
| 场景 | 还需要 Config 吗? | 原因 |
|---|---|---|
| 用了 Nacos 做注册+配置 | ❌ 不需要 | Nacos 已经覆盖了 Config 的全部功能 |
| 需要配置加密 | ⚠️ 可选 | Config 有内置加密,但 Jasypt/Vault 更合适 |
| 需要 Git 审计追溯 | ⚠️ 可选 | Nacos 有历史版本,但 Git 审计更强 |
| 已有 Git 运维体系 | ⚠️ 可选 | 如果团队极度依赖 Git 做 change review |
| 用了 Eureka 做注册 | ✅ 需要 | 用 Config 做配置管理是标准组合 |
| 混用两套体系 | ❌ 不建议 | 架构复杂度增加,维护成本翻倍 |
标准组合推荐:
方案 A:Spring Cloud 原生方案
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Eureka │ │ Config │ │ Bus │
│ 服务发现 │ │ 配置管理 │ │ 配置广播 │
└──────────┘ └──────────┘ └──────────┘
方案 B:Spring Cloud Alibaba 方案(推荐)
┌──────────────────────┐
│ Nacos │
│ 服务发现 + 配置管理 │
└──────────────────────┘
一个组件搞定两个功能,运维成本最低
方案 C:自建 + Nacos 混合(不推荐)
┌──────────┐ ┌──────────┐
│ Config │ │ Nacos │
│ 配置管理?│ │ 配置管理?│ ← 两个配置中心,冲突
└──────────┘ └──────────┘
方案 D:Nacos + Vault(加密场景)
┌──────────┐ ┌──────────┐
│ Nacos │ │ Vault │
│ 普通配置 │ │ 敏感配置 │ ← 职责清晰,不冲突
└──────────┘ └──────────┘一句话:Nacos 已经包含了 Config 的能力,两者选一个即可。除非你有 Git 审计或加密的特殊需求,否则不需要同时使用。
九、面试要点
Q1:Config 配置刷新的原理?
调用 /actuator/refresh 时,@RefreshScope 标注的 Bean 会被重新初始化。底层通过 ContextRefresher.refresh() 重新加载 Environment 中的配置,并销毁重建 RefreshScope 中的 Bean。
Q2:bootstrap.yml 和 application.yml 的区别?
bootstrap.yml 优先级更高,在应用启动的引导阶段加载,用于获取 Config Server 地址等引导配置。application.yml 在引导完成后加载。Spring Boot 3.x 中 bootstrap 默认不启用,需要引入 spring-cloud-starter-bootstrap。
Q3:Config Server 高可用怎么做?
部署多个 Config Server 实例,前面挂一个 LoadBalancer。客户端通过 spring.cloud.config.uri 配置多个地址,或通过服务发现(Eureka/Nacos)自动发现 Config Server 实例。
Q4:Git 不可用时怎么办?
Config Server 会使用本地缓存(basedir 指定的目录)。设置 clone-on-start: true 确保启动时已 clone 成功。配合 fail-fast: true 在网络问题时快速感知。
