Spring Cloud 配置中心详解
一、知识概述
配置中心是微服务架构中管理分布式系统配置的核心组件,它实现了配置的集中管理、动态更新和环境隔离。Spring Cloud 提供了 Spring Cloud Config 和支持 Nacos 等配置中心的集成方案。
配置中心的核心功能:
- 集中管理:统一管理所有服务的配置
- 动态更新:无需重启即可更新配置
- 环境隔离:开发、测试、生产环境配置隔离
- 版本管理:配置变更历史追溯
理解配置中心的原理和使用方式,是构建可维护微服务系统的重要技能。
二、知识点详细讲解
2.1 配置中心对比
| 特性 | Spring Cloud Config | Nacos | Apollo |
|---|---|---|---|
| 配置存储 | Git/SVN | 数据库 | 数据库 |
| 动态刷新 | 需要总线 | 原生支持 | 原生支持 |
| 灰度发布 | ❌ | ✅ | ✅ |
| 权限管理 | Git 权限 | ✅ | ✅ |
| 多环境 | Profile | Namespace | Env |
| 学习成本 | 低 | 低 | 中 |
2.2 Spring Cloud Config 架构
配置客户端 Config Server Git/SVN
│ │ │
│──── 获取配置 ──────────>│ │
│ │──── 拉取配置 ──────────>│
│ │ │
│<─── 返回配置 ───────────│<─── 返回配置 ───────────│
│ │ │
│──── 刷新通知 ──────────>│ │
│ │ │
2.3 配置优先级
1. 命令行参数
2. Java 系统属性
3. 环境变量
4. 外部配置文件
5. 内部配置文件
6. @PropertySource
7. 默认属性
2.4 配置文件加载顺序
1. bootstrap.yml(启动配置)
2. application.yml(应用配置)
3. application-{profile}.yml(环境配置)
4. 配置中心配置
5. 命令行参数
三、代码示例
3.1 Spring Cloud Config Server
<!-- pom.xml -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
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);
}
}
# application.yml
server:
port: 8888
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://github.com/example/config-repo
search-paths: '{application}'
default-label: main
username: ${GIT_USERNAME}
password: ${GIT_PASSWORD}
clone-on-start: true
basedir: /tmp/config-repo
# 本地文件系统配置(开发环境)
# config:
# server:
# native:
# search-locations: classpath:/config
# profiles:
# active: native
3.2 Spring Cloud Config Client
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
# bootstrap.yml
spring:
application:
name: user-service
profiles:
active: dev
cloud:
config:
uri: http://localhost:8888
label: main
fail-fast: true
retry:
initial-interval: 1000
max-interval: 2000
max-attempts: 6
multiplier: 1.1
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;
@RestController
@RefreshScope // 支持动态刷新
public class ConfigController {
@Value("${app.message:default}")
private String message;
@Value("${app.timeout:3000}")
private int timeout;
@GetMapping("/config")
public Map<String, Object> getConfig() {
Map<String, Object> config = new HashMap<>();
config.put("message", message);
config.put("timeout", timeout);
return config;
}
}
3.3 动态刷新配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
# 暴露 refresh 端点
management:
endpoints:
web:
exposure:
include: refresh,health,info
// 方式1:使用 @RefreshScope
@RestController
@RefreshScope
public class RefreshController {
@Value("${dynamic.config}")
private String dynamicConfig;
@GetMapping("/dynamic")
public String getDynamicConfig() {
return dynamicConfig;
}
}
// 方式2:使用 Environment
@Component
public class ConfigManager {
@Autowired
private Environment environment;
public String getConfig(String key) {
return environment.getProperty(key);
}
}
// 方式3:使用 @ConfigurationProperties
@Component
@ConfigurationProperties(prefix = "app")
@RefreshScope
public class AppProperties {
private String name;
private String version;
private Map<String, String> features = new HashMap<>();
// getter/setter
}
# 手动触发刷新
curl -X POST http://localhost:8080/actuator/refresh
3.4 Nacos 配置中心
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
# bootstrap.yml
spring:
application:
name: user-service
profiles:
active: dev
cloud:
nacos:
config:
server-addr: localhost:8848
namespace: dev
group: DEFAULT_GROUP
file-extension: yaml
refresh-enabled: true
# 扩展配置
shared-configs:
- data-id: common.yaml
group: DEFAULT_GROUP
refresh: true
# 扩展配置(优先级更高)
extension-configs:
- data-id: redis.yaml
group: DEFAULT_GROUP
refresh: true
- data-id: mysql.yaml
group: DEFAULT_GROUP
refresh: true
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;
@RestController
@RefreshScope
public class NacosConfigController {
@Value("${user.config.name}")
private String name;
@Value("${user.config.max-connections}")
private int maxConnections;
@GetMapping("/nacos-config")
public Map<String, Object> getNacosConfig() {
Map<String, Object> config = new HashMap<>();
config.put("name", name);
config.put("maxConnections", maxConnections);
return config;
}
}
3.5 配置监听
import com.alibaba.nacos.api.config.annotation.NacosConfigListener;
import org.springframework.stereotype.Component;
@Component
public class NacosConfigListener {
@NacosConfigListener(dataId = "user-service.yaml", groupId = "DEFAULT_GROUP")
public void onConfigChange(String newConfig) {
System.out.println("配置变更: " + newConfig);
// 处理配置变更逻辑
}
@NacosConfigListener(dataId = "user-service.yaml")
public void onConfigChange(Properties properties) {
System.out.println("配置变更(Properties 格式):");
properties.forEach((key, value) -> {
System.out.println(" " + key + " = " + value);
});
}
}
3.6 多环境配置
# bootstrap.yml
spring:
application:
name: user-service
cloud:
nacos:
config:
server-addr: localhost:8848
namespace: ${NACOS_NAMESPACE:dev} # 环境变量控制
group: DEFAULT_GROUP
file-extension: yaml
// 使用 Profile 注解控制
@Configuration
@Profile("dev")
public class DevConfig {
// 开发环境配置
}
@Configuration
@Profile("prod")
public class ProdConfig {
// 生产环境配置
}
3.7 配置加密
import org.jasypt.encryption.StringEncryptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ConfigEncryptService {
@Autowired
private StringEncryptor encryptor;
// 加密配置
public String encrypt(String plainText) {
return encryptor.encrypt(plainText);
}
// 解密配置
public String decrypt(String encryptedText) {
return encryptor.decrypt(encryptedText);
}
}
# application.yml
# 加密配置格式:ENC(加密内容)
database:
password: ENC(加密后的密码)
jasypt:
encryptor:
password: ${JASYPT_PASSWORD} # 加密密钥
algorithm: PBEWithMD5AndDES
3.8 配置版本管理
import org.springframework.cloud.config.client.ConfigClientProperties;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.web.bind.annotation.*;
@RestController
public class ConfigVersionController {
@Autowired
private ConfigClientProperties configClientProperties;
@GetMapping("/config/info")
public Map<String, Object> getConfigInfo() {
Map<String, Object> info = new HashMap<>();
info.put("name", configClientProperties.getName());
info.put("profile", configClientProperties.getProfile());
info.put("label", configClientProperties.getLabel());
info.put("uri", configClientProperties.getUri());
return info;
}
}
四、实战应用场景
4.1 配置中心高可用
# Config Server 多实例配置
spring:
cloud:
config:
server:
git:
uri: https://github.com/example/config-repo
discovery:
enabled: true
service-id: config-server
# 客户端配置
spring:
cloud:
config:
discovery:
enabled: true
service-id: config-server
fail-fast: true
retry:
max-attempts: 10
4.2 配置变更通知
import org.springframework.cloud.bus.event.RefreshRemoteApplicationEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class ConfigChangeListener {
@EventListener
public void onRefreshEvent(RefreshRemoteApplicationEvent event) {
System.out.println("收到配置刷新事件: " + event.getDestinationService());
// 处理配置变更
}
}
<!-- 需要引入 Spring Cloud Bus -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
4.3 配置灰度发布
import com.alibaba.nacos.api.config.annotation.NacosConfigListener;
import org.springframework.stereotype.Component;
@Component
public class GrayConfigListener {
@NacosConfigListener(dataId = "gray-config.yaml")
public void onGrayConfigChange(String config) {
// 解析灰度配置
GrayConfig grayConfig = parseGrayConfig(config);
// 应用灰度配置
applyGrayConfig(grayConfig);
}
private GrayConfig parseGrayConfig(String config) {
// 解析配置
return new GrayConfig();
}
private void applyGrayConfig(GrayConfig config) {
// 应用配置
}
}
class GrayConfig {
private List<String> grayUsers;
private String grayVersion;
private int grayPercentage;
// getter/setter
}
4.4 配置回滚
import org.springframework.cloud.config.client.ConfigServicePropertySourceLocator;
import org.springframework.core.env.PropertySource;
import org.springframework.stereotype.Service;
@Service
public class ConfigRollbackService {
@Autowired
private ConfigServicePropertySourceLocator locator;
private final Map<String, PropertySource<?>> configHistory = new ConcurrentHashMap<>();
// 保存当前配置
public void saveCurrentConfig(String version) {
PropertySource<?> source = locator.locate(new Environment("default"));
configHistory.put(version, source);
}
// 回滚到指定版本
public void rollback(String version) {
PropertySource<?> source = configHistory.get(version);
if (source != null) {
// 应用历史配置
applyConfig(source);
}
}
private void applyConfig(PropertySource<?> source) {
// 应用配置逻辑
}
}
4.5 配置校验
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.*;
@Component
@ConfigurationProperties(prefix = "app")
@Validated
public class AppConfig {
@NotBlank(message = "应用名称不能为空")
private String name;
@Min(value = 1, message = "最小连接数为 1")
@Max(value = 100, message = "最大连接数为 100")
private int maxConnections = 10;
@Pattern(regexp = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}$",
message = "邮箱格式不正确")
private String adminEmail;
@NotNull
private List<@NotBlank String> allowedOrigins;
// getter/setter
}
五、总结与最佳实践
配置中心选择
| 场景 | 推荐 |
|---|---|
| 简单项目 | Spring Cloud Config + Git |
| 需要动态刷新 | Nacos |
| 需要灰度发布 | Apollo |
| 已有 Nacos | Nacos Config |
最佳实践
- 敏感配置:使用加密存储
- 版本管理:保留配置变更历史
- 权限控制:配置修改需要审批
- 灰度发布:先在小范围验证
配置中心是微服务架构的重要基础设施,选择合适的配置中心方案,合理管理配置,能够大大提高系统的可维护性和可扩展性。