第 225 章:Spring Cloud Config 与配置中心
学习目标
- 掌握 Spring Cloud Config
- 学会使用 Nacos Config
- 实现配置的动态刷新
- 配置加解密
一、配置中心定位
1.1 为什么需要配置中心
| 痛点 | 配置中心解决 |
|---|---|
| 配置散落各服务 | 集中管理 |
| 改配置需重启 | 动态刷新 |
| 多环境不一致 | 环境隔离 |
| 密钥明文存储 | 加密存储 |
| 修改无审计 | 版本追踪 |
1.2 对比
| 产品 | 后端存储 | 动态刷新 | 易用度 |
|---|---|---|---|
| Spring Cloud Config | Git | 需 Bus | 简单 |
| Nacos Config | MySQL | 自动 | ⭐⭐⭐⭐ |
| Apollo | MySQL | 自动 + Web | ⭐⭐⭐⭐⭐ |
| Consul KV | Raft | watch | 中 |
二、Spring Cloud Config
2.1 服务端
依赖:
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>配置:
yaml
server:
port: 8888
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://github.com/myorg/config-repo
username: ${git-user}
password: ${git-pass}
default-label: main
search-paths: '{application}'启动类:
java
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication { ... }2.2 客户端
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>bootstrap.yml:
yaml
spring:
application:
name: order-service
cloud:
config:
uri: http://localhost:8888
profile: dev
label: main2.3 客户端配置加载顺序
三、Nacos Config(推荐)
3.1 引入
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>3.2 bootstrap.yml
yaml
spring:
application:
name: order-service
profiles:
active: dev
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
namespace: prod
group: DEFAULT_GROUP
file-extension: yaml
refresh-enabled: true
# 拓展配置(优先级高于主配置)
extension-configs:
- data-id: order-datasource.yaml
refresh: true
# 共享配置
shared-configs:
- data-id: common.yaml
refresh: true
- data-id: redis.yaml
refresh: true3.3 DataId 规则
${spring.application.name}-${spring.profiles.active}.${file-extension}
↓
order-service-dev.yaml
# 还可以有:
order-service.yaml # 默认
order-service-prod.yaml # 生产环境3.4 配置内容
Nacos 控制台 配置管理 → 配置列表:
yaml
# order-service-dev.yaml
server:
port: 8081
spring:
datasource:
url: jdbc:mysql://dev-mysql:3306/order
username: dev
password: dev
order:
timeout: 3000
maxRetry: 2
feature:
recommendEnabled: true3.5 配置加载优先级
数值越小优先级越高。
四、动态刷新
4.1 单 Bean 刷新
java
@RestController
@RefreshScope // 关键注解
public class OrderController {
@Value("${order.timeout}")
private int timeout;
@GetMapping("/config")
public String config() {
return "timeout=" + timeout;
}
}改 Nacos 配置后,30 秒内 Bean 重新创建,生效。
4.2 批量 Bean 刷新
java
@Configuration
@RefreshScope
public class OrderConfig {
@Bean
@RefreshScope
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder
.setConnectTimeout(Duration.ofMillis(timeout))
.setReadTimeout(Duration.ofMillis(timeout))
.build();
}
}4.3 自定义刷新逻辑
java
@Component
@Slf4j
public class ConfigChangeListener implements ApplicationRunner {
@Autowired
private Environment env;
@Override
public void run(ApplicationArguments args) {
NacosFactory.createConfigService("127.0.0.1:8848")
.addListener("order-service.yaml", "DEFAULT_GROUP", new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
log.info("配置变化: {}", configInfo);
// 重新读取
String timeout = env.getProperty("order.timeout");
// 执行自定义逻辑
cacheService.refreshAll();
}
});
}
}五、配置加密
5.1 Jasypt(对称加密)
xml
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.4</version>
</dependency>yaml
jasypt:
encryptor:
password: ${JASYPT_PASSWORD}java
// 启动类
@SpringBootApplication
@EnableEncryptableProperties
public class Application { ... }
// 测试加密
@Autowired
private StringEncryptor encryptor;
public void test() {
String enc = encryptor.encrypt("mySecretPass");
System.out.println(enc); // ENC(R6b...)
}yaml
# Nacos 中配置
spring:
datasource:
password: ENC(R6bV1O5...) # 加密值
# 环境变量传入密钥
JASYPT_PASSWORD=my-master-pass5.2 自定义加密
java
@Bean
public StringEncryptor stringEncryptor() {
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
config.setPassword("my-master-pass");
config.setAlgorithm("PBEWithMD5AndDES");
config.setKeyObtentionIterations("1000");
config.setPoolSize("1");
encryptor.setConfig(config);
return encryptor;
}5.3 加密方案选型
| 方案 | 特点 |
|---|---|
| Jasypt | 简单,对称加密 |
| Vault | HashiCorp,生产级 |
| Nacos KMS | 阿里云一体化 |
| KMS 服务 | 自建服务统一管理 |
六、配置规范
6.1 命名规范
yaml
# 推荐用点分隔
spring.datasource.url
spring.datasource.hikari.max-pool-size
# 不推荐(应用层用)
datasourceUrl6.2 分层管理
yaml
# common.yaml(所有服务共享)
spring.application.name=...
spring.main.banner-mode=off
server.servlet.encoding.charset=UTF-8
# datasource.yaml(基础设施)
spring.datasource.url=...
spring.datasource.username=...
# order-service.yaml(业务)
order.timeout=5000
order.max-retry=36.3 必读 vs 可选
yaml
# 必读 → bootstrap.yml(启动时)
spring.application.name
spring.cloud.nacos.config.server-addr
spring.profiles.active
# 可选 → application.yml / Nacos
业务配置、日志级别、连接池参数6.4 避免敏感信息
yaml
# ❌ 不要把密钥直接写在配置
spring.datasource.password: root123
# ✅ 通过环境变量或加密
spring.datasource.password: ${DB_PASS}七、监听变更总线:Bus
@RefreshScope 只刷新当前服务实例。Bus 让配置变更广播到所有实例。
xml
<!-- Config Server + Bus -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-monitor</artifactId>
</dependency>yaml
spring:
rabbitmq:
host: localhost
port: 5672
management:
endpoints:
web:
exposure:
include: bus-refresh触发刷新:
bash
curl -X POST http://config-server/actuator/busrefresh所有服务实例同时收到消息,触发配置刷新。
八、灰度配置推送
Nacos 支持配置灰度发布。
bash
# 通过 Nacos OpenAPI 实现
curl -X POST 'http://nacos:8848/nacos/v1/cs/configs' \
-d 'dataId=order-service.yaml&group=DEFAULT_GROUP&content=...&beta=true'九、配置审计
9.1 Nacos 操作审计
控制台 权限管理 → 操作日志 查询变更历史。
9.2 Spring Boot Audit
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>java
@Aspect
@Component
public class ConfigAudit {
@Autowired
private AuditLogRepository auditLogRepo;
@Before("@annotation(org.springframework.cloud.context.config.annotation.RefreshScope)")
public void auditRefresh(JoinPoint jp) {
AuditLog log = new AuditLog();
log.setAction("CONFIG_REFRESH");
log.setUser(SecurityContextHolder.getContext().getAuthentication().getName());
auditLogRepo.save(log);
}
}十、Spring Cloud 全家桶图
十一、配置最佳实践
11.1 使用 application-{profile}.yaml
yaml
# bootstrap.yml - 只放启动必需的配置
spring:
cloud:
nacos:
config:
file-extension: yaml
# application-dev.yml
spring:
datasource:
url: jdbc:mysql://dev-mysql/...11.2 启动前必检
java
@Component
public class ConfigValidator implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment env, SpringApplication app) {
// 检查关键配置是否存在
List<String> required = List.of(
"spring.datasource.url",
"spring.datasource.password"
);
required.forEach(key -> {
if (env.getProperty(key) == null) {
throw new IllegalStateException("Missing required config: " + key);
}
});
}
}11.3 启动失败快速定位
yaml
# 调试模式打印所有配置源
logging:
level:
org.springframework.cloud: DEBUG十二、本章小结
| 组件 | 作用 |
|---|---|
| Config Server | Git 后端配置中心 |
| Nacos Config | 一体化(注册+配置) |
| Apollo | 携程开源,功能强 |
| @RefreshScope | Bean 级配置刷新 |
| Bus | 全实例刷新广播 |
| Jasypt | 配置加密 |
动手练习
- 用 Nacos Config 做订单服务的配置中心
- 配置动态刷新,修改 Nacos 验证 Bean 自动刷新
- 用 Jasypt 加密数据库密码
- 写一个监听器,配置变更时清空本地缓存