Spring Cloud Config 配置中心
导学
"小崔,数据库连接密码改了,你改一下所有微服务的配置。"白歌说。
小崔:"我们有 12 个微服务,每个服务有 3 个环境(dev/test/prod),每个服务部署了 5 个实例...我得改 12 × 3 = 36 个配置文件,然后重启 12 × 5 = 60 个实例。"
白歌:"先别改。我们用 Spring Cloud Config 统一管理配置,改一次就生效。"
定位与问题场景
微服务架构下配置管理的痛点:
| 痛点 | 传统方案 | Config 方案 |
|---|---|---|
| 配置分散 | 每个服务各自维护 application.yml | 统一存储在 Git 仓库 |
| 环境切换 | 手动替换配置文件 | 通过 profile 自动切换 |
| 配置变更 | 修改配置文件 + 重启服务 | 修改 Git + 触发刷新(无需重启) |
| 敏感配置 | 明文写在配置文件中 | 支持加密存储 |
| 审计 | 无 | Git 历史记录天然审计 |
Config 核心原理
整体架构
配置加载优先级
Config Client 加载配置的顺序(后者覆盖前者):
- 本地
bootstrap.yml(连接 Config Server 的配置) - Config Server 返回的
application.yml(所有服务公共配置) - Config Server 返回的
{application}-{profile}.yml(服务专属配置) - 本地
application.yml(本地覆盖,优先级最高)
完整示例:飞翔科技统一配置管理
场景描述
飞翔科技 12 个微服务的配置统一存放在 Git 仓库,Config Server 作为配置中心对外提供服务。
操作前后对比:
| 维度 | 引入 Config 前 | 引入 Config 后 |
|---|---|---|
| 配置存储 | 散落在各服务的 application.yml | 集中 Git 仓库 |
| 修改数据库密码 | 改 36 个文件 + 重启 60 个实例 | 改 1 个 Git 文件 + Bus 广播刷新 |
| 环境切换 | 手动改 spring.profiles.active | Git 分支/目录隔离 |
步骤一:Git 仓库配置结构
feixiang-config-repo/
├── application.yml # 所有服务公共配置
├── feixiang-order-service-dev.yml # 订单服务 dev 环境
├── feixiang-order-service-prod.yml # 订单服务 prod 环境
├── feixiang-inventory-service-dev.yml
├── feixiang-inventory-service-prod.yml
└── feixiang-payment-service-dev.yml
feixiang-order-service-dev.yml 示例:
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/feixiang_order_dev
username: dev_user
password: '{cipher}AQBx...' # 加密存储
# 业务配置
feixiang:
order:
max-items-per-order: 10
payment-timeout-seconds: 300
步骤二:搭建 Config Server
依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
启动类:
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
配置:
server:
port: 8888
spring:
application:
name: feixiang-config-server
cloud:
config:
server:
git:
uri: https://gitee.com/feixiang/feixiang-config-repo.git
username: feixiang-dev
password: ${GIT_PASSWORD} # 通过环境变量注入
search-paths: '{application}' # 支持子目录
default-label: main # 默认分支
clone-on-start: true # 启动时克隆,首次请求更快
force-pull: true # 强制拉取(本地有修改也可覆盖)
验证:
curl http://localhost:8888/feixiang-order-service/dev
# 返回合并后的配置 JSON
步骤三:Config Client 接入
依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
bootstrap.yml(Config Client 连接 Server 的配置):
spring:
application:
name: feixiang-order-service # 对应 Git 中的文件名前缀
cloud:
config:
uri: http://localhost:8888 # Config Server 地址
profile: dev # 环境标识
label: main # Git 分支
fail-fast: true # 连接 Config Server 失败时启动失败
retry:
initial-interval: 1000
max-attempts: 6
业务代码读取配置:
@RefreshScope // 支持运行时刷新
@RestController
public class OrderController {
@Value("${feixiang.order.max-items-per-order}")
private int maxItems;
@GetMapping("/order/config")
public Map<String, Object> getConfig() {
return Map.of("maxItemsPerOrder", maxItems);
}
}
步骤四:配置动态刷新
方案一:单点刷新(开发环境)
curl -X POST http://localhost:8080/actuator/refresh
@RefreshScope 标注的 Bean 会在 refresh 后重新创建。
方案二:Bus 批量刷新(生产环境)
添加 spring-cloud-starter-bus-amqp,配置 RabbitMQ:
spring:
rabbitmq:
host: localhost
port: 5672
username: admin
password: admin
在 Config Server 添加 Webhook 端点:
curl -X POST http://localhost:8888/monitor \
-H "X-GitHub-Event: push" \
-H "Content-Type: application/json" \
-d '{"commits":[{"modified":["feixiang-order-service-dev.yml"]}]}'
Config Server 检测到变更后通过 Bus 广播 RefreshRemoteApplicationEvent,所有客户端自动刷新配置。
易错场景
1. bootstrap.yml 不生效
Spring Cloud 2020.0.x 起默认禁用了 Bootstrap。需手动引入:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
2. @RefreshScope 标注的 Bean 未刷新
@RefreshScope 仅对 @Value 注入的属性生效。如果是 @ConfigurationProperties,需要重建整个 Bean。确认:
- Actuator 已引入且端点未禁用
@RefreshScope标注在正确的类上- 被刷新的属性确实来自 Config Server(非本地文件)
3. Config Server 缓存导致最新配置未生效
Config Server 默认缓存 Git 仓库内容,可用 force-pull: true 强制拉取。
4. 加密配置的密钥管理
encrypt:
key: ${ENCRYPT_KEY} # 对称加密密钥,禁止硬编码,通过环境变量注入
# 加密
curl localhost:8888/encrypt -d 'mypassword'
# 解密
curl localhost:8888/decrypt -d 'AQBx...'
面试考点
@RefreshScope 的底层原理?
@RefreshScope是@Scope("refresh")的快捷方式,被标注的 Bean 放入 Spring 的 Refresh Scope 中。当调用/actuator/refresh时,Spring Cloud 会清空 Refresh Scope 的缓存,销毁其中的 Bean。下次访问时,Spring 会重新创建 Bean,此时重新读取配置源(Config Server)获取最新值,从而实现了"伪热更新"。
Spring Cloud Bus 如何实现集群配置刷新?
Bus 基于消息中间件(RabbitMQ / Kafka)实现事件广播。当 Config Server 收到 Webhook 通知或手动触发
/monitor端点后,发布RefreshRemoteApplicationEvent到消息总线。所有连接到同一消息中间件的微服务实例会收到该事件,自动执行本地配置刷新。这解决了"逐个实例调用 /actuator/refresh"的问题。
Config Server 高可用方案?
- Config Server 集群:部署多个 Config Server 实例,客户端通过 LoadBalancer 访问
- 客户端配置多个 Config Server URI:
spring.cloud.config.uri[0]、spring.cloud.config.uri[1]- Config Server 注册到 Eureka/Nacos,客户端通过服务发现
- Git 仓库高可用:GitHub/GitLab 本身保证,或使用本地镜像
Config Server 与 Nacos 配置中心的对比?
Config Server Nacos Config 配置存储在 Git 配置存储在 Nacos Server(MySQL) 刷新依赖 Bus + Webhook 长轮询(Long Polling),实时推送 无自带 UI 内置管理控制台 纯 Spring Cloud 生态 Spring Cloud Alibaba 生态 适合已有 Git 运维体系的团队 适合希望注册+配置一体化的团队
小结
Spring Cloud Config 通过"配置外部化 + Git 版本控制 + Bus 事件广播"解决了微服务配置管理的三大痛点:集中管理、版本审计、动态刷新。但它的实时推送依赖消息总线,配置批量变更时需要触发广播。如果你的团队已经或计划使用 Nacos,Nacos Config 的实时推送和可视化管理可能更吸引人。下一章进入 API 网关,看看外部流量如何统一进入微服务体系。