27-Spring Cloud 配置中心详解

0 阅读3分钟

Spring Cloud 配置中心详解

一、知识概述

配置中心是微服务架构中管理分布式系统配置的核心组件,它实现了配置的集中管理、动态更新和环境隔离。Spring Cloud 提供了 Spring Cloud Config 和支持 Nacos 等配置中心的集成方案。

配置中心的核心功能:

  • 集中管理:统一管理所有服务的配置
  • 动态更新:无需重启即可更新配置
  • 环境隔离:开发、测试、生产环境配置隔离
  • 版本管理:配置变更历史追溯

理解配置中心的原理和使用方式,是构建可维护微服务系统的重要技能。

二、知识点详细讲解

2.1 配置中心对比

特性Spring Cloud ConfigNacosApollo
配置存储Git/SVN数据库数据库
动态刷新需要总线原生支持原生支持
灰度发布
权限管理Git 权限
多环境ProfileNamespaceEnv
学习成本

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
已有 NacosNacos Config

最佳实践

  1. 敏感配置:使用加密存储
  2. 版本管理:保留配置变更历史
  3. 权限控制:配置修改需要审批
  4. 灰度发布:先在小范围验证

配置中心是微服务架构的重要基础设施,选择合适的配置中心方案,合理管理配置,能够大大提高系统的可维护性和可扩展性。