学习目标

通过本章学习,你将能够: - 理解 Nacos 与 Spring Cloud 的集成原理 - 掌握 Spring Cloud Alibaba 的使用 - 实现服务注册与发现的集成 - 配置动态配置管理 - 实现负载均衡和服务调用 - 掌握配置热更新和服务治理

1. 集成概述

1.1 Spring Cloud Alibaba 简介

from enum import Enum
from dataclasses import dataclass, field
from typing import List, Dict, Optional, Any, Callable
import time
import threading
import json
import random
from datetime import datetime

class ServiceStatus(Enum):
    """服务状态枚举"""
    UP = "UP"                    # 服务正常
    DOWN = "DOWN"                # 服务下线
    OUT_OF_SERVICE = "OUT_OF_SERVICE"  # 服务停止
    UNKNOWN = "UNKNOWN"          # 状态未知

class LoadBalanceStrategy(Enum):
    """负载均衡策略枚举"""
    ROUND_ROBIN = "ROUND_ROBIN"  # 轮询
    RANDOM = "RANDOM"            # 随机
    WEIGHTED_RANDOM = "WEIGHTED_RANDOM"  # 加权随机
    LEAST_ACTIVE = "LEAST_ACTIVE"        # 最少活跃
    CONSISTENT_HASH = "CONSISTENT_HASH"  # 一致性哈希

class ConfigFormat(Enum):
    """配置格式枚举"""
    PROPERTIES = "properties"    # Properties 格式
    YAML = "yaml"                # YAML 格式
    JSON = "json"                # JSON 格式
    XML = "xml"                  # XML 格式
    TEXT = "text"                # 纯文本格式

class RefreshScope(Enum):
    """刷新范围枚举"""
    SINGLETON = "singleton"      # 单例刷新
    PROTOTYPE = "prototype"      # 原型刷新
    REQUEST = "request"          # 请求范围刷新
    SESSION = "session"          # 会话范围刷新

@dataclass
class ServiceInstance:
    """服务实例信息"""
    service_id: str              # 服务 ID
    instance_id: str             # 实例 ID
    host: str                    # 主机地址
    port: int                    # 端口号
    secure: bool = False         # 是否使用 HTTPS
    metadata: Dict[str, str] = field(default_factory=dict)
    status: ServiceStatus = ServiceStatus.UP
    weight: float = 1.0          # 权重
    cluster_name: str = "DEFAULT"  # 集群名称
    namespace_id: str = "public"   # 命名空间
    group_name: str = "DEFAULT_GROUP"  # 分组名称
    ephemeral: bool = True       # 是否临时实例
    enabled: bool = True         # 是否启用
    healthy: bool = True         # 是否健康
    
    def get_uri(self) -> str:
        """获取服务 URI"""
        scheme = "https" if self.secure else "http"
        return f"{scheme}://{self.host}:{self.port}"
    
    def get_service_url(self, path: str = "") -> str:
        """获取服务完整 URL"""
        base_uri = self.get_uri()
        if path.startswith("/"):
            return f"{base_uri}{path}"
        return f"{base_uri}/{path}" if path else base_uri

@dataclass
class ConfigProperty:
    """配置属性"""
    data_id: str                 # 配置 ID
    group: str = "DEFAULT_GROUP" # 配置分组
    namespace_id: str = "public" # 命名空间
    content: str = ""            # 配置内容
    config_type: ConfigFormat = ConfigFormat.PROPERTIES
    timeout: int = 3000          # 超时时间
    auto_refresh: bool = True    # 自动刷新
    refresh_scope: RefreshScope = RefreshScope.SINGLETON
    listeners: List[Callable[[str], None]] = field(default_factory=list)
    last_modified: float = field(default_factory=time.time)
    
    def add_listener(self, listener: Callable[[str], None]):
        """添加配置变更监听器"""
        self.listeners.append(listener)
    
    def notify_change(self, new_content: str):
        """通知配置变更"""
        old_content = self.content
        self.content = new_content
        self.last_modified = time.time()
        
        for listener in self.listeners:
            try:
                listener(new_content)
            except Exception as e:
                print(f"配置变更监听器执行失败: {e}")

@dataclass
class CircuitBreakerConfig:
    """熔断器配置"""
    failure_threshold: int = 5   # 失败阈值
    timeout: int = 60000         # 超时时间(毫秒)
    retry_timeout: int = 10000   # 重试超时(毫秒)
    success_threshold: int = 3   # 成功阈值
    enabled: bool = True         # 是否启用

class SpringCloudNacosIntegration:
    """Spring Cloud Nacos 集成管理器"""
    
    def __init__(self, server_addr: str = "localhost:8848", 
                 namespace: str = "public"):
        self.server_addr = server_addr
        self.namespace = namespace
        self.services: Dict[str, List[ServiceInstance]] = {}
        self.configs: Dict[str, ConfigProperty] = {}
        self.load_balancer_strategy = LoadBalanceStrategy.ROUND_ROBIN
        self.circuit_breaker_config = CircuitBreakerConfig()
        self._lock = threading.RLock()
        self._running = False
        self._threads = []
        
    def start(self):
        """启动集成服务"""
        with self._lock:
            if self._running:
                print("⚠️ Spring Cloud Nacos 集成已经在运行中")
                return
            
            self._running = True
            
            # 启动服务发现线程
            discovery_thread = threading.Thread(target=self._service_discovery_worker, daemon=True)
            discovery_thread.start()
            self._threads.append(discovery_thread)
            
            # 启动配置监听线程
            config_thread = threading.Thread(target=self._config_listener_worker, daemon=True)
            config_thread.start()
            self._threads.append(config_thread)
            
            # 启动健康检查线程
            health_thread = threading.Thread(target=self._health_check_worker, daemon=True)
            health_thread.start()
            self._threads.append(health_thread)
            
            print(f"✅ Spring Cloud Nacos 集成启动成功")
    
    def stop(self):
        """停止集成服务"""
        with self._lock:
            if not self._running:
                print("⚠️ Spring Cloud Nacos 集成未在运行")
                return
            
            self._running = False
            
            # 等待线程结束
            for thread in self._threads:
                if thread.is_alive():
                    thread.join(timeout=5)
            
            print(f"✅ Spring Cloud Nacos 集成已停止")
    
    def register_service(self, service_instance: ServiceInstance) -> bool:
        """注册服务实例"""
        with self._lock:
            service_id = service_instance.service_id
            
            if service_id not in self.services:
                self.services[service_id] = []
            
            # 检查实例是否已存在
            for instance in self.services[service_id]:
                if (instance.host == service_instance.host and 
                    instance.port == service_instance.port):
                    print(f"⚠️ 服务实例已存在: {service_instance.instance_id}")
                    return False
            
            self.services[service_id].append(service_instance)
            print(f"✅ 服务注册成功: {service_instance.service_id} - {service_instance.get_uri()}")
            return True
    
    def deregister_service(self, service_id: str, instance_id: str) -> bool:
        """注销服务实例"""
        with self._lock:
            if service_id not in self.services:
                print(f"❌ 服务不存在: {service_id}")
                return False
            
            instances = self.services[service_id]
            for i, instance in enumerate(instances):
                if instance.instance_id == instance_id:
                    instances.pop(i)
                    print(f"✅ 服务注销成功: {instance_id}")
                    
                    # 如果没有实例了,删除服务
                    if not instances:
                        del self.services[service_id]
                    
                    return True
            
            print(f"❌ 服务实例不存在: {instance_id}")
            return False
    
    def discover_services(self, service_id: str) -> List[ServiceInstance]:
        """发现服务实例"""
        with self._lock:
            if service_id not in self.services:
                return []
            
            # 返回健康的实例
            healthy_instances = []
            for instance in self.services[service_id]:
                if instance.enabled and instance.healthy and instance.status == ServiceStatus.UP:
                    healthy_instances.append(instance)
            
            return healthy_instances
    
    def get_service_instance(self, service_id: str) -> Optional[ServiceInstance]:
        """根据负载均衡策略获取服务实例"""
        instances = self.discover_services(service_id)
        
        if not instances:
            print(f"❌ 没有可用的服务实例: {service_id}")
            return None
        
        return self._select_instance(instances)
    
    def _select_instance(self, instances: List[ServiceInstance]) -> ServiceInstance:
        """根据负载均衡策略选择实例"""
        if self.load_balancer_strategy == LoadBalanceStrategy.ROUND_ROBIN:
            return self._round_robin_select(instances)
        elif self.load_balancer_strategy == LoadBalanceStrategy.RANDOM:
            return random.choice(instances)
        elif self.load_balancer_strategy == LoadBalanceStrategy.WEIGHTED_RANDOM:
            return self._weighted_random_select(instances)
        else:
            return instances[0]
    
    def _round_robin_select(self, instances: List[ServiceInstance]) -> ServiceInstance:
        """轮询选择"""
        if not hasattr(self, '_round_robin_index'):
            self._round_robin_index = 0
        
        instance = instances[self._round_robin_index % len(instances)]
        self._round_robin_index += 1
        return instance
    
    def _weighted_random_select(self, instances: List[ServiceInstance]) -> ServiceInstance:
        """加权随机选择"""
        total_weight = sum(instance.weight for instance in instances)
        if total_weight == 0:
            return random.choice(instances)
        
        random_weight = random.uniform(0, total_weight)
        current_weight = 0
        
        for instance in instances:
            current_weight += instance.weight
            if current_weight >= random_weight:
                return instance
        
        return instances[-1]
    
    def register_config(self, config_property: ConfigProperty):
        """注册配置"""
        with self._lock:
            config_key = f"{config_property.data_id}#{config_property.group}#{config_property.namespace_id}"
            self.configs[config_key] = config_property
            print(f"✅ 配置注册成功: {config_property.data_id}")
    
    def get_config(self, data_id: str, group: str = "DEFAULT_GROUP", 
                   namespace_id: str = "public") -> Optional[str]:
        """获取配置"""
        with self._lock:
            config_key = f"{data_id}#{group}#{namespace_id}"
            if config_key in self.configs:
                return self.configs[config_key].content
            return None
    
    def update_config(self, data_id: str, content: str, group: str = "DEFAULT_GROUP", 
                     namespace_id: str = "public") -> bool:
        """更新配置"""
        with self._lock:
            config_key = f"{data_id}#{group}#{namespace_id}"
            if config_key in self.configs:
                config_property = self.configs[config_key]
                config_property.notify_change(content)
                print(f"✅ 配置更新成功: {data_id}")
                return True
            
            print(f"❌ 配置不存在: {data_id}")
            return False
    
    def add_config_listener(self, data_id: str, listener: Callable[[str], None], 
                           group: str = "DEFAULT_GROUP", namespace_id: str = "public"):
        """添加配置监听器"""
        with self._lock:
            config_key = f"{data_id}#{group}#{namespace_id}"
            if config_key in self.configs:
                self.configs[config_key].add_listener(listener)
                print(f"✅ 配置监听器添加成功: {data_id}")
            else:
                print(f"❌ 配置不存在: {data_id}")
    
    def _service_discovery_worker(self):
        """服务发现工作线程"""
        while self._running:
            try:
                # 模拟服务发现更新
                with self._lock:
                    for service_id, instances in self.services.items():
                        for instance in instances:
                            # 模拟实例状态变化
                            if random.random() < 0.05:  # 5% 概率状态变化
                                if instance.status == ServiceStatus.UP:
                                    instance.status = ServiceStatus.DOWN
                                    instance.healthy = False
                                    print(f"⚠️ 服务实例状态变为 DOWN: {instance.instance_id}")
                                else:
                                    instance.status = ServiceStatus.UP
                                    instance.healthy = True
                                    print(f"✅ 服务实例状态恢复 UP: {instance.instance_id}")
                
                time.sleep(10)  # 每10秒检查一次
            except Exception as e:
                print(f"❌ 服务发现工作线程异常: {e}")
                time.sleep(1)
    
    def _config_listener_worker(self):
        """配置监听工作线程"""
        while self._running:
            try:
                # 模拟配置变更
                with self._lock:
                    for config_key, config_property in self.configs.items():
                        if config_property.auto_refresh and random.random() < 0.02:  # 2% 概率配置变更
                            new_content = f"updated_content_{int(time.time())}"
                            config_property.notify_change(new_content)
                            print(f"🔄 配置自动更新: {config_property.data_id}")
                
                time.sleep(30)  # 每30秒检查一次
            except Exception as e:
                print(f"❌ 配置监听工作线程异常: {e}")
                time.sleep(1)
    
    def _health_check_worker(self):
        """健康检查工作线程"""
        while self._running:
            try:
                with self._lock:
                    for service_id, instances in self.services.items():
                        for instance in instances:
                            # 模拟健康检查
                            if random.random() < 0.1:  # 10% 概率健康状态变化
                                instance.healthy = not instance.healthy
                                status = "健康" if instance.healthy else "不健康"
                                print(f"🏥 健康检查: {instance.instance_id} - {status}")
                
                time.sleep(15)  # 每15秒检查一次
            except Exception as e:
                print(f"❌ 健康检查工作线程异常: {e}")
                time.sleep(1)
    
    def get_service_statistics(self) -> Dict[str, Any]:
        """获取服务统计信息"""
        with self._lock:
            stats = {
                "total_services": len(self.services),
                "total_instances": sum(len(instances) for instances in self.services.values()),
                "healthy_instances": 0,
                "total_configs": len(self.configs),
                "services": {},
                "load_balancer_strategy": self.load_balancer_strategy.value
            }
            
            for service_id, instances in self.services.items():
                healthy_count = sum(1 for instance in instances if instance.healthy)
                stats["healthy_instances"] += healthy_count
                
                stats["services"][service_id] = {
                    "total_instances": len(instances),
                    "healthy_instances": healthy_count,
                    "instances": [
                        {
                            "instance_id": instance.instance_id,
                            "uri": instance.get_uri(),
                            "status": instance.status.value,
                            "healthy": instance.healthy,
                            "weight": instance.weight
                        }
                        for instance in instances
                    ]
                }
            
            return stats

# 使用示例
if __name__ == "__main__":
    # 创建 Spring Cloud Nacos 集成
    integration = SpringCloudNacosIntegration("localhost:8848", "public")
    
    print("=== Spring Cloud Nacos 集成示例 ===")
    
    # 启动集成服务
    integration.start()
    
    # 注册服务实例
    user_service_1 = ServiceInstance(
        service_id="user-service",
        instance_id="user-service-1",
        host="192.168.1.101",
        port=8080,
        weight=1.0,
        metadata={"version": "1.0.0", "zone": "zone-a"}
    )
    
    user_service_2 = ServiceInstance(
        service_id="user-service",
        instance_id="user-service-2",
        host="192.168.1.102",
        port=8080,
        weight=1.5,
        metadata={"version": "1.0.0", "zone": "zone-b"}
    )
    
    order_service = ServiceInstance(
        service_id="order-service",
        instance_id="order-service-1",
        host="192.168.1.103",
        port=8081,
        weight=1.0,
        metadata={"version": "2.0.0", "zone": "zone-a"}
    )
    
    integration.register_service(user_service_1)
    integration.register_service(user_service_2)
    integration.register_service(order_service)
    
    # 注册配置
    database_config = ConfigProperty(
        data_id="database.properties",
        group="DEFAULT_GROUP",
        namespace_id="public",
        content="spring.datasource.url=jdbc:mysql://localhost:3306/test\nspring.datasource.username=root",
        config_type=ConfigFormat.PROPERTIES,
        auto_refresh=True
    )
    
    redis_config = ConfigProperty(
        data_id="redis.yaml",
        group="DEFAULT_GROUP",
        namespace_id="public",
        content="redis:\n  host: localhost\n  port: 6379\n  timeout: 3000",
        config_type=ConfigFormat.YAML,
        auto_refresh=True
    )
    
    integration.register_config(database_config)
    integration.register_config(redis_config)
    
    # 添加配置监听器
    def on_database_config_change(new_content: str):
        print(f"📝 数据库配置变更: {new_content[:50]}...")
    
    def on_redis_config_change(new_content: str):
        print(f"📝 Redis 配置变更: {new_content[:50]}...")
    
    integration.add_config_listener("database.properties", on_database_config_change)
    integration.add_config_listener("redis.yaml", on_redis_config_change)
    
    # 服务发现测试
    print("\n=== 服务发现测试 ===")
    
    for i in range(5):
        instance = integration.get_service_instance("user-service")
        if instance:
            print(f"请求 {i+1}: {instance.instance_id} - {instance.get_uri()}")
        time.sleep(1)
    
    # 配置获取测试
    print("\n=== 配置管理测试 ===")
    
    db_config = integration.get_config("database.properties")
    print(f"数据库配置: {db_config[:50]}...")
    
    redis_config_content = integration.get_config("redis.yaml")
    print(f"Redis 配置: {redis_config_content[:50]}...")
    
    # 配置更新测试
    print("\n=== 配置更新测试 ===")
    
    new_db_config = "spring.datasource.url=jdbc:mysql://localhost:3306/prod\nspring.datasource.username=admin"
    integration.update_config("database.properties", new_db_config)
    
    # 等待一段时间观察自动更新
    print("\n=== 等待自动更新 ===")
    time.sleep(35)
    
    # 显示统计信息
    print("\n=== 服务统计信息 ===")
    stats = integration.get_service_statistics()
    print(f"总服务数: {stats['total_services']}")
    print(f"总实例数: {stats['total_instances']}")
    print(f"健康实例数: {stats['healthy_instances']}")
    print(f"总配置数: {stats['total_configs']}")
    print(f"负载均衡策略: {stats['load_balancer_strategy']}")
    
    for service_id, service_info in stats['services'].items():
        print(f"\n服务 {service_id}:")
        print(f"  实例数: {service_info['total_instances']}")
        print(f"  健康实例数: {service_info['healthy_instances']}")
        for instance_info in service_info['instances']:
            print(f"    - {instance_info['instance_id']}: {instance_info['uri']} ({instance_info['status']})")
    
    # 停止集成服务
    time.sleep(5)
    integration.stop()

2. 项目配置

2.1 Maven 依赖配置

<!-- pom.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>com.example</groupId>
    <artifactId>nacos-spring-cloud-demo</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>
    
    <name>Nacos Spring Cloud Demo</name>
    <description>Nacos Spring Cloud Integration Demo</description>
    
    <properties>
        <java.version>11</java.version>
        <spring-boot.version>2.7.8</spring-boot.version>
        <spring-cloud.version>2021.0.5</spring-cloud.version>
        <spring-cloud-alibaba.version>2021.0.4.0</spring-cloud-alibaba.version>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    
    <dependencyManagement>
        <dependencies>
            <!-- Spring Boot BOM -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            
            <!-- Spring Cloud BOM -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            
            <!-- Spring Cloud Alibaba BOM -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <dependencies>
        <!-- Spring Boot Starter Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <!-- Spring Boot Starter Actuator -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        
        <!-- Spring Cloud Starter Bootstrap -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
        
        <!-- Nacos Discovery -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        
        <!-- Nacos Config -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        
        <!-- Spring Cloud Loadbalancer -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
        
        <!-- Spring Cloud OpenFeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        
        <!-- Spring Cloud Circuit Breaker -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
        </dependency>
        
        <!-- Spring Cloud Gateway (可选) -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        
        <!-- Spring Boot Configuration Processor -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        
        <!-- Validation -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        
        <!-- JSON Processing -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        
        <!-- Test Dependencies -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-contract-stub-runner</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.springframework.boot</groupId>
                            <artifactId>spring-boot-configuration-processor</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
            
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.10.1</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>
            
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M8</version>
                <configuration>
                    <skipTests>false</skipTests>
                </configuration>
            </plugin>
        </plugins>
    </build>
    
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <releases>
                <enabled>false</enabled>
            </releases>
        </repository>
    </repositories>
    
    <pluginRepositories>
        <pluginRepository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
        
        <pluginRepository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <releases>
                <enabled>false</enabled>
            </releases>
        </pluginRepository>
    </pluginRepositories>
</project>

2.2 应用配置文件

# bootstrap.yml
# Bootstrap 配置文件,优先级高于 application.yml
spring:
  application:
    name: nacos-spring-cloud-demo
  profiles:
    active: dev
  cloud:
    nacos:
      # 服务发现配置
      discovery:
        server-addr: localhost:8848
        namespace: public
        group: DEFAULT_GROUP
        cluster-name: DEFAULT
        service: ${spring.application.name}
        weight: 1
        network-interface: eth0
        ip: 192.168.1.100
        port: ${server.port:8080}
        secure: false
        access-key: 
        secret-key: 
        log-name: nacos-discovery.log
        endpoint: 
        metadata:
          version: 1.0.0
          zone: zone-a
          cluster: default
        watch-delay: 30000
        heart-beat-interval: 5000
        heart-beat-timeout: 15000
        ip-delete-timeout: 30000
        instance-enabled: true
        ephemeral: true
        
      # 配置管理配置
      config:
        server-addr: localhost:8848
        namespace: public
        group: DEFAULT_GROUP
        prefix: ${spring.application.name}
        file-extension: yml
        timeout: 3000
        max-retry: 3
        config-retry-time: 2000
        config-long-poll-timeout: 46000
        enable-remote-sync-config: true
        access-key: 
        secret-key: 
        endpoint: 
        
        # 扩展配置
        extension-configs:
          - data-id: database.yml
            group: DEFAULT_GROUP
            refresh: true
          - data-id: redis.yml
            group: DEFAULT_GROUP
            refresh: true
          - data-id: mq.yml
            group: DEFAULT_GROUP
            refresh: true
            
        # 共享配置
        shared-configs:
          - data-id: common.yml
            group: DEFAULT_GROUP
            refresh: true
          - data-id: logging.yml
            group: DEFAULT_GROUP
            refresh: true

# 日志配置
logging:
  level:
    com.alibaba.nacos: DEBUG
    org.springframework.cloud.alibaba: DEBUG
    com.example: DEBUG
  pattern:
    console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
    file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
  file:
    name: logs/nacos-spring-cloud-demo.log
    max-size: 100MB
    max-history: 30
# application.yml
# 应用主配置文件
server:
  port: 8080
  servlet:
    context-path: /api
  tomcat:
    max-threads: 200
    min-spare-threads: 10
    max-connections: 8192
    accept-count: 100
    connection-timeout: 20000

spring:
  application:
    name: nacos-spring-cloud-demo
  
  # 数据源配置(从 Nacos 配置中心获取)
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: password
    hikari:
      minimum-idle: 5
      maximum-pool-size: 20
      auto-commit: true
      idle-timeout: 30000
      pool-name: DatebookHikariCP
      max-lifetime: 1800000
      connection-timeout: 30000
      connection-test-query: SELECT 1
  
  # Redis 配置(从 Nacos 配置中心获取)
  redis:
    host: localhost
    port: 6379
    password: 
    timeout: 3000ms
    database: 0
    lettuce:
      pool:
        max-active: 8
        max-wait: -1ms
        max-idle: 8
        min-idle: 0
  
  # Jackson 配置
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
    default-property-inclusion: non_null
    serialization:
      write-dates-as-timestamps: false
      fail-on-empty-beans: false
    deserialization:
      fail-on-unknown-properties: false
  
  # Cloud 配置
  cloud:
    # 负载均衡配置
    loadbalancer:
      ribbon:
        enabled: false
      cache:
        enabled: true
        ttl: 35s
        capacity: 256
      health-check:
        initial-delay: 0
        interval: 25s
        
    # OpenFeign 配置
    openfeign:
      client:
        config:
          default:
            connect-timeout: 5000
            read-timeout: 10000
            logger-level: basic
          user-service:
            connect-timeout: 3000
            read-timeout: 8000
            logger-level: full
      compression:
        request:
          enabled: true
          mime-types: text/xml,application/xml,application/json
          min-request-size: 2048
        response:
          enabled: true
      metrics:
        enabled: true
      
    # 熔断器配置
    circuitbreaker:
      resilience4j:
        enabled: true
      instances:
        user-service:
          failure-rate-threshold: 50
          wait-duration-in-open-state: 30s
          sliding-window-size: 10
          minimum-number-of-calls: 5
          permitted-number-of-calls-in-half-open-state: 3
          automatic-transition-from-open-to-half-open-enabled: true
          
    # Gateway 配置(如果使用网关)
    gateway:
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/user/**
          filters:
            - StripPrefix=1
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/order/**
          filters:
            - StripPrefix=1

# 监控配置
management:
  endpoints:
    web:
      exposure:
        include: '*'
  endpoint:
    health:
      show-details: always
    metrics:
      enabled: true
  metrics:
    export:
      prometheus:
        enabled: true
    distribution:
      percentiles-histogram:
        http.server.requests: true
      percentiles:
        http.server.requests: 0.5, 0.9, 0.95, 0.99
  health:
    nacos:
      enabled: true

# Feign 日志配置
feign:
  client:
    config:
      default:
        logger-level: BASIC
  httpclient:
    enabled: true
    max-connections: 200
    max-connections-per-route: 50
    connection-timeout: 2000
    connection-timer-repeat: 3000
  compression:
    request:
      enabled: true
    response:
      enabled: true

# 自定义配置
app:
  name: ${spring.application.name}
  version: 1.0.0
  description: Nacos Spring Cloud Integration Demo
  author: Developer
  
  # 业务配置
  business:
    user:
      default-page-size: 20
      max-page-size: 100
      cache-ttl: 300
    order:
      timeout: 30
      retry-times: 3
      
  # 安全配置
  security:
    jwt:
      secret: mySecretKey
      expiration: 86400
    cors:
      allowed-origins: "*"
      allowed-methods: GET,POST,PUT,DELETE,OPTIONS
      allowed-headers: "*"
      max-age: 3600

2.3 环境特定配置

# application-dev.yml
# 开发环境配置
spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        namespace: dev
      config:
        server-addr: localhost:8848
        namespace: dev
        
logging:
  level:
    root: INFO
    com.example: DEBUG
    com.alibaba.nacos: DEBUG
    
app:
  business:
    user:
      cache-ttl: 60  # 开发环境缓存时间短
# application-test.yml
# 测试环境配置
spring:
  cloud:
    nacos:
      discovery:
        server-addr: nacos-test.example.com:8848
        namespace: test
      config:
        server-addr: nacos-test.example.com:8848
        namespace: test
        
logging:
  level:
    root: WARN
    com.example: INFO
    
app:
  business:
    user:
      cache-ttl: 180  # 测试环境中等缓存时间
# application-prod.yml
# 生产环境配置
spring:
  cloud:
    nacos:
      discovery:
        server-addr: nacos-prod.example.com:8848
        namespace: prod
        cluster-name: PROD
      config:
        server-addr: nacos-prod.example.com:8848
        namespace: prod
        
logging:
  level:
    root: WARN
    com.example: INFO
    
app:
  business:
    user:
      cache-ttl: 600  # 生产环境缓存时间长
      
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus

3. 服务注册与发现

3.1 服务提供者

// UserServiceApplication.java
// 用户服务应用主类
package com.example.userservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class UserServiceApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
    
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
// User.java
// 用户实体类
package com.example.userservice.entity;

import com.fasterxml.jackson.annotation.JsonFormat;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.time.LocalDateTime;

public class User {
    
    private Long id;
    
    @NotBlank(message = "用户名不能为空")
    @Size(min = 3, max = 20, message = "用户名长度必须在3-20之间")
    private String username;
    
    @NotBlank(message = "邮箱不能为空")
    @Email(message = "邮箱格式不正确")
    private String email;
    
    private String phone;
    
    private Integer status;
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;
    
    // 构造函数
    public User() {}
    
    public User(Long id, String username, String email) {
        this.id = id;
        this.username = username;
        this.email = email;
        this.status = 1;
        this.createTime = LocalDateTime.now();
        this.updateTime = LocalDateTime.now();
    }
    
    // Getter 和 Setter 方法
    public Long getId() {
        return id;
    }
    
    public void setId(Long id) {
        this.id = id;
    }
    
    public String getUsername() {
        return username;
    }
    
    public void setUsername(String username) {
        this.username = username;
    }
    
    public String getEmail() {
        return email;
    }
    
    public void setEmail(String email) {
        this.email = email;
    }
    
    public String getPhone() {
        return phone;
    }
    
    public void setPhone(String phone) {
        this.phone = phone;
    }
    
    public Integer getStatus() {
        return status;
    }
    
    public void setStatus(Integer status) {
        this.status = status;
    }
    
    public LocalDateTime getCreateTime() {
        return createTime;
    }
    
    public void setCreateTime(LocalDateTime createTime) {
        this.createTime = createTime;
    }
    
    public LocalDateTime getUpdateTime() {
        return updateTime;
    }
    
    public void setUpdateTime(LocalDateTime updateTime) {
        this.updateTime = updateTime;
    }
    
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", email='" + email + '\'' +
                ", phone='" + phone + '\'' +
                ", status=" + status +
                ", createTime=" + createTime +
                ", updateTime=" + updateTime +
                '}';
    }
}
// UserService.java
// 用户服务接口
package com.example.userservice.service;

import com.example.userservice.entity.User;
import java.util.List;

public interface UserService {
    
    /**
     * 根据 ID 获取用户
     */
    User getUserById(Long id);
    
    /**
     * 根据用户名获取用户
     */
    User getUserByUsername(String username);
    
    /**
     * 获取所有用户
     */
    List<User> getAllUsers();
    
    /**
     * 创建用户
     */
    User createUser(User user);
    
    /**
     * 更新用户
     */
    User updateUser(Long id, User user);
    
    /**
     * 删除用户
     */
    boolean deleteUser(Long id);
    
    /**
     * 分页查询用户
     */
    List<User> getUsersByPage(int page, int size);
}
// UserServiceImpl.java
// 用户服务实现类
package com.example.userservice.service.impl;

import com.example.userservice.entity.User;
import com.example.userservice.service.UserService;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements UserService {
    
    // 模拟数据库存储
    private final Map<Long, User> userStorage = new ConcurrentHashMap<>();
    private Long nextId = 1L;
    
    public UserServiceImpl() {
        // 初始化一些测试数据
        initTestData();
    }
    
    private void initTestData() {
        createUser(new User(null, "admin", "admin@example.com"));
        createUser(new User(null, "user1", "user1@example.com"));
        createUser(new User(null, "user2", "user2@example.com"));
    }
    
    @Override
    public User getUserById(Long id) {
        return userStorage.get(id);
    }
    
    @Override
    public User getUserByUsername(String username) {
        return userStorage.values().stream()
                .filter(user -> user.getUsername().equals(username))
                .findFirst()
                .orElse(null);
    }
    
    @Override
    public List<User> getAllUsers() {
        return new ArrayList<>(userStorage.values());
    }
    
    @Override
    public User createUser(User user) {
        user.setId(nextId++);
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        user.setStatus(1);
        userStorage.put(user.getId(), user);
        return user;
    }
    
    @Override
    public User updateUser(Long id, User user) {
        User existingUser = userStorage.get(id);
        if (existingUser != null) {
            user.setId(id);
            user.setCreateTime(existingUser.getCreateTime());
            user.setUpdateTime(LocalDateTime.now());
            userStorage.put(id, user);
            return user;
        }
        return null;
    }
    
    @Override
    public boolean deleteUser(Long id) {
        return userStorage.remove(id) != null;
    }
    
    @Override
    public List<User> getUsersByPage(int page, int size) {
        List<User> allUsers = getAllUsers();
        int start = page * size;
        int end = Math.min(start + size, allUsers.size());
        
        if (start >= allUsers.size()) {
            return Collections.emptyList();
        }
        
        return allUsers.subList(start, end);
    }
}
// UserController.java
// 用户控制器
package com.example.userservice.controller;

import com.example.userservice.entity.User;
import com.example.userservice.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/users")
@RefreshScope
@Validated
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @Value("${app.business.user.default-page-size:20}")
    private int defaultPageSize;
    
    @Value("${app.business.user.max-page-size:100}")
    private int maxPageSize;
    
    @Value("${spring.application.name}")
    private String serviceName;
    
    @Value("${server.port}")
    private String serverPort;
    
    /**
     * 获取服务信息
     */
    @GetMapping("/info")
    public ResponseEntity<Map<String, Object>> getServiceInfo() {
        Map<String, Object> info = new HashMap<>();
        info.put("serviceName", serviceName);
        info.put("serverPort", serverPort);
        info.put("timestamp", System.currentTimeMillis());
        info.put("defaultPageSize", defaultPageSize);
        info.put("maxPageSize", maxPageSize);
        return ResponseEntity.ok(info);
    }
    
    /**
     * 根据 ID 获取用户
     */
    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable @Min(1) Long id) {
        User user = userService.getUserById(id);
        if (user != null) {
            return ResponseEntity.ok(user);
        }
        return ResponseEntity.notFound().build();
    }
    
    /**
     * 根据用户名获取用户
     */
    @GetMapping("/username/{username}")
    public ResponseEntity<User> getUserByUsername(@PathVariable String username) {
        User user = userService.getUserByUsername(username);
        if (user != null) {
            return ResponseEntity.ok(user);
        }
        return ResponseEntity.notFound().build();
    }
    
    /**
     * 获取所有用户
     */
    @GetMapping
    public ResponseEntity<List<User>> getAllUsers() {
        List<User> users = userService.getAllUsers();
        return ResponseEntity.ok(users);
    }
    
    /**
     * 分页查询用户
     */
    @GetMapping("/page")
    public ResponseEntity<Map<String, Object>> getUsersByPage(
            @RequestParam(defaultValue = "0") @Min(0) int page,
            @RequestParam(defaultValue = "20") @Min(1) int size) {
        
        // 限制页面大小
        if (size > maxPageSize) {
            size = maxPageSize;
        }
        
        List<User> users = userService.getUsersByPage(page, size);
        int total = userService.getAllUsers().size();
        
        Map<String, Object> result = new HashMap<>();
        result.put("content", users);
        result.put("page", page);
        result.put("size", size);
        result.put("total", total);
        result.put("totalPages", (total + size - 1) / size);
        result.put("serviceName", serviceName);
        result.put("serverPort", serverPort);
        
        return ResponseEntity.ok(result);
    }
    
    /**
     * 创建用户
     */
    @PostMapping
    public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
        User createdUser = userService.createUser(user);
        return ResponseEntity.ok(createdUser);
    }
    
    /**
     * 更新用户
     */
    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(@PathVariable @Min(1) Long id, 
                                          @Valid @RequestBody User user) {
        User updatedUser = userService.updateUser(id, user);
        if (updatedUser != null) {
            return ResponseEntity.ok(updatedUser);
        }
        return ResponseEntity.notFound().build();
    }
    
    /**
     * 删除用户
     */
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable @Min(1) Long id) {
        boolean deleted = userService.deleteUser(id);
        if (deleted) {
            return ResponseEntity.ok().build();
        }
        return ResponseEntity.notFound().build();
    }
    
    /**
     * 健康检查
     */
    @GetMapping("/health")
    public ResponseEntity<Map<String, Object>> health() {
        Map<String, Object> health = new HashMap<>();
        health.put("status", "UP");
        health.put("serviceName", serviceName);
        health.put("serverPort", serverPort);
        health.put("timestamp", System.currentTimeMillis());
        health.put("userCount", userService.getAllUsers().size());
        return ResponseEntity.ok(health);
    }
}

3.2 服务消费者

// OrderServiceApplication.java
// 订单服务应用主类
package com.example.orderservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderServiceApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }
    
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
// UserServiceClient.java
// 用户服务 Feign 客户端
package com.example.orderservice.client;

import com.example.orderservice.entity.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;

@FeignClient(name = "user-service", path = "/api/users")
public interface UserServiceClient {
    
    @GetMapping("/info")
    Map<String, Object> getServiceInfo();
    
    @GetMapping("/{id}")
    User getUserById(@PathVariable("id") Long id);
    
    @GetMapping("/username/{username}")
    User getUserByUsername(@PathVariable("username") String username);
    
    @GetMapping
    List<User> getAllUsers();
    
    @GetMapping("/page")
    Map<String, Object> getUsersByPage(@RequestParam("page") int page, 
                                      @RequestParam("size") int size);
    
    @PostMapping
    User createUser(@RequestBody User user);
    
    @PutMapping("/{id}")
    User updateUser(@PathVariable("id") Long id, @RequestBody User user);
    
    @DeleteMapping("/{id}")
    void deleteUser(@PathVariable("id") Long id);
    
    @GetMapping("/health")
    Map<String, Object> health();
}
// Order.java
// 订单实体类
package com.example.orderservice.entity;

import com.fasterxml.jackson.annotation.JsonFormat;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDateTime;

public class Order {
    
    private Long id;
    
    @NotNull(message = "用户ID不能为空")
    private Long userId;
    
    private String orderNo;
    
    @DecimalMin(value = "0.01", message = "订单金额必须大于0")
    private BigDecimal amount;
    
    private Integer status; // 0-待支付, 1-已支付, 2-已取消
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;
    
    // 关联用户信息(非持久化字段)
    private User user;
    
    // 构造函数
    public Order() {}
    
    public Order(Long userId, BigDecimal amount) {
        this.userId = userId;
        this.amount = amount;
        this.status = 0;
        this.createTime = LocalDateTime.now();
        this.updateTime = LocalDateTime.now();
        this.orderNo = generateOrderNo();
    }
    
    private String generateOrderNo() {
        return "ORD" + System.currentTimeMillis() + (int)(Math.random() * 1000);
    }
    
    // Getter 和 Setter 方法
    public Long getId() {
        return id;
    }
    
    public void setId(Long id) {
        this.id = id;
    }
    
    public Long getUserId() {
        return userId;
    }
    
    public void setUserId(Long userId) {
        this.userId = userId;
    }
    
    public String getOrderNo() {
        return orderNo;
    }
    
    public void setOrderNo(String orderNo) {
        this.orderNo = orderNo;
    }
    
    public BigDecimal getAmount() {
        return amount;
    }
    
    public void setAmount(BigDecimal amount) {
        this.amount = amount;
    }
    
    public Integer getStatus() {
        return status;
    }
    
    public void setStatus(Integer status) {
        this.status = status;
    }
    
    public LocalDateTime getCreateTime() {
        return createTime;
    }
    
    public void setCreateTime(LocalDateTime createTime) {
        this.createTime = createTime;
    }
    
    public LocalDateTime getUpdateTime() {
        return updateTime;
    }
    
    public void setUpdateTime(LocalDateTime updateTime) {
        this.updateTime = updateTime;
    }
    
    public User getUser() {
        return user;
    }
    
    public void setUser(User user) {
        this.user = user;
    }
    
    @Override
    public String toString() {
        return "Order{" +
                "id=" + id +
                ", userId=" + userId +
                ", orderNo='" + orderNo + '\'' +
                ", amount=" + amount +
                ", status=" + status +
                ", createTime=" + createTime +
                ", updateTime=" + updateTime +
                '}';
    }
}
// User.java
// 用户实体类(订单服务中的副本)
package com.example.orderservice.entity;

import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDateTime;

public class User {
    
    private Long id;
    private String username;
    private String email;
    private String phone;
    private Integer status;
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;
    
    // 构造函数
    public User() {}
    
    public User(Long id, String username, String email) {
        this.id = id;
        this.username = username;
        this.email = email;
    }
    
    // Getter 和 Setter 方法
    public Long getId() {
        return id;
    }
    
    public void setId(Long id) {
        this.id = id;
    }
    
    public String getUsername() {
        return username;
    }
    
    public void setUsername(String username) {
        this.username = username;
    }
    
    public String getEmail() {
        return email;
    }
    
    public void setEmail(String email) {
        this.email = email;
    }
    
    public String getPhone() {
        return phone;
    }
    
    public void setPhone(String phone) {
        this.phone = phone;
    }
    
    public Integer getStatus() {
        return status;
    }
    
    public void setStatus(Integer status) {
        this.status = status;
    }
    
    public LocalDateTime getCreateTime() {
        return createTime;
    }
    
    public void setCreateTime(LocalDateTime createTime) {
        this.createTime = createTime;
    }
    
    public LocalDateTime getUpdateTime() {
        return updateTime;
    }
    
    public void setUpdateTime(LocalDateTime updateTime) {
        this.updateTime = updateTime;
    }
}
// OrderService.java
// 订单服务接口
package com.example.orderservice.service;

import com.example.orderservice.entity.Order;
import java.util.List;

public interface OrderService {
    
    Order createOrder(Order order);
    
    Order getOrderById(Long id);
    
    List<Order> getOrdersByUserId(Long userId);
    
    List<Order> getAllOrders();
    
    Order updateOrderStatus(Long id, Integer status);
    
    boolean deleteOrder(Long id);
}
// OrderServiceImpl.java
// 订单服务实现类
package com.example.orderservice.service.impl;

import com.example.orderservice.client.UserServiceClient;
import com.example.orderservice.entity.Order;
import com.example.orderservice.entity.User;
import com.example.orderservice.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Service
public class OrderServiceImpl implements OrderService {
    
    @Autowired
    private UserServiceClient userServiceClient;
    
    // 模拟数据库存储
    private final Map<Long, Order> orderStorage = new ConcurrentHashMap<>();
    private Long nextId = 1L;
    
    @Override
    public Order createOrder(Order order) {
        // 验证用户是否存在
        try {
            User user = userServiceClient.getUserById(order.getUserId());
            if (user == null) {
                throw new RuntimeException("用户不存在: " + order.getUserId());
            }
            
            order.setId(nextId++);
            order.setCreateTime(LocalDateTime.now());
            order.setUpdateTime(LocalDateTime.now());
            order.setUser(user);
            
            orderStorage.put(order.getId(), order);
            return order;
        } catch (Exception e) {
            throw new RuntimeException("创建订单失败: " + e.getMessage(), e);
        }
    }
    
    @Override
    public Order getOrderById(Long id) {
        Order order = orderStorage.get(id);
        if (order != null) {
            // 填充用户信息
            try {
                User user = userServiceClient.getUserById(order.getUserId());
                order.setUser(user);
            } catch (Exception e) {
                // 用户服务不可用时,不影响订单查询
                System.err.println("获取用户信息失败: " + e.getMessage());
            }
        }
        return order;
    }
    
    @Override
    public List<Order> getOrdersByUserId(Long userId) {
        return orderStorage.values().stream()
                .filter(order -> order.getUserId().equals(userId))
                .collect(Collectors.toList());
    }
    
    @Override
    public List<Order> getAllOrders() {
        return new ArrayList<>(orderStorage.values());
    }
    
    @Override
    public Order updateOrderStatus(Long id, Integer status) {
        Order order = orderStorage.get(id);
        if (order != null) {
            order.setStatus(status);
            order.setUpdateTime(LocalDateTime.now());
            return order;
        }
        return null;
    }
    
    @Override
    public boolean deleteOrder(Long id) {
        return orderStorage.remove(id) != null;
    }
}
// OrderController.java
// 订单控制器
package com.example.orderservice.controller;

import com.example.orderservice.client.UserServiceClient;
import com.example.orderservice.entity.Order;
import com.example.orderservice.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/orders")
@RefreshScope
@Validated
public class OrderController {
    
    @Autowired
    private OrderService orderService;
    
    @Autowired
    private UserServiceClient userServiceClient;
    
    @Value("${app.business.order.timeout:30}")
    private int orderTimeout;
    
    @Value("${app.business.order.retry-times:3}")
    private int retryTimes;
    
    @Value("${spring.application.name}")
    private String serviceName;
    
    @Value("${server.port}")
    private String serverPort;
    
    /**
     * 获取服务信息
     */
    @GetMapping("/info")
    public ResponseEntity<Map<String, Object>> getServiceInfo() {
        Map<String, Object> info = new HashMap<>();
        info.put("serviceName", serviceName);
        info.put("serverPort", serverPort);
        info.put("timestamp", System.currentTimeMillis());
        info.put("orderTimeout", orderTimeout);
        info.put("retryTimes", retryTimes);
        
        // 调用用户服务获取信息
        try {
            Map<String, Object> userServiceInfo = userServiceClient.getServiceInfo();
            info.put("userServiceInfo", userServiceInfo);
        } catch (Exception e) {
            info.put("userServiceError", e.getMessage());
        }
        
        return ResponseEntity.ok(info);
    }
    
    /**
     * 创建订单
     */
    @PostMapping
    public ResponseEntity<Order> createOrder(@Valid @RequestBody Order order) {
        try {
            Order createdOrder = orderService.createOrder(order);
            return ResponseEntity.ok(createdOrder);
        } catch (Exception e) {
            return ResponseEntity.badRequest().build();
        }
    }
    
    /**
     * 根据 ID 获取订单
     */
    @GetMapping("/{id}")
    public ResponseEntity<Order> getOrderById(@PathVariable @Min(1) Long id) {
        Order order = orderService.getOrderById(id);
        if (order != null) {
            return ResponseEntity.ok(order);
        }
        return ResponseEntity.notFound().build();
    }
    
    /**
     * 根据用户 ID 获取订单
     */
    @GetMapping("/user/{userId}")
    public ResponseEntity<List<Order>> getOrdersByUserId(@PathVariable @Min(1) Long userId) {
        List<Order> orders = orderService.getOrdersByUserId(userId);
        return ResponseEntity.ok(orders);
    }
    
    /**
     * 获取所有订单
     */
    @GetMapping
    public ResponseEntity<List<Order>> getAllOrders() {
        List<Order> orders = orderService.getAllOrders();
        return ResponseEntity.ok(orders);
    }
    
    /**
     * 更新订单状态
     */
    @PutMapping("/{id}/status")
    public ResponseEntity<Order> updateOrderStatus(@PathVariable @Min(1) Long id, 
                                                   @RequestParam Integer status) {
        Order updatedOrder = orderService.updateOrderStatus(id, status);
        if (updatedOrder != null) {
            return ResponseEntity.ok(updatedOrder);
        }
        return ResponseEntity.notFound().build();
    }
    
    /**
     * 删除订单
     */
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteOrder(@PathVariable @Min(1) Long id) {
        boolean deleted = orderService.deleteOrder(id);
        if (deleted) {
            return ResponseEntity.ok().build();
        }
        return ResponseEntity.notFound().build();
    }
    
    /**
     * 健康检查
     */
    @GetMapping("/health")
    public ResponseEntity<Map<String, Object>> health() {
        Map<String, Object> health = new HashMap<>();
        health.put("status", "UP");
        health.put("serviceName", serviceName);
        health.put("serverPort", serverPort);
        health.put("timestamp", System.currentTimeMillis());
        health.put("orderCount", orderService.getAllOrders().size());
        
        // 检查用户服务健康状态
        try {
            Map<String, Object> userHealth = userServiceClient.health();
            health.put("userServiceHealth", userHealth);
        } catch (Exception e) {
            health.put("userServiceHealth", "DOWN");
            health.put("userServiceError", e.getMessage());
        }
        
        return ResponseEntity.ok(health);
    }
}

4. 配置热更新

4.1 配置属性类

// AppProperties.java
// 应用配置属性类
package com.example.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "app")
@RefreshScope
public class AppProperties {
    
    private String name;
    private String version;
    private String description;
    private String author;
    
    private Business business = new Business();
    private Security security = new Security();
    
    public static class Business {
        private User user = new User();
        private Order order = new Order();
        
        public static class User {
            private int defaultPageSize = 20;
            private int maxPageSize = 100;
            private int cacheTtl = 300;
            
            // Getter 和 Setter
            public int getDefaultPageSize() {
                return defaultPageSize;
            }
            
            public void setDefaultPageSize(int defaultPageSize) {
                this.defaultPageSize = defaultPageSize;
            }
            
            public int getMaxPageSize() {
                return maxPageSize;
            }
            
            public void setMaxPageSize(int maxPageSize) {
                this.maxPageSize = maxPageSize;
            }
            
            public int getCacheTtl() {
                return cacheTtl;
            }
            
            public void setCacheTtl(int cacheTtl) {
                this.cacheTtl = cacheTtl;
            }
        }
        
        public static class Order {
            private int timeout = 30;
            private int retryTimes = 3;
            
            // Getter 和 Setter
            public int getTimeout() {
                return timeout;
            }
            
            public void setTimeout(int timeout) {
                this.timeout = timeout;
            }
            
            public int getRetryTimes() {
                return retryTimes;
            }
            
            public void setRetryTimes(int retryTimes) {
                this.retryTimes = retryTimes;
            }
        }
        
        // Getter 和 Setter
        public User getUser() {
            return user;
        }
        
        public void setUser(User user) {
            this.user = user;
        }
        
        public Order getOrder() {
            return order;
        }
        
        public void setOrder(Order order) {
            this.order = order;
        }
    }
    
    public static class Security {
        private Jwt jwt = new Jwt();
        private Cors cors = new Cors();
        
        public static class Jwt {
            private String secret = "mySecretKey";
            private long expiration = 86400;
            
            // Getter 和 Setter
            public String getSecret() {
                return secret;
            }
            
            public void setSecret(String secret) {
                this.secret = secret;
            }
            
            public long getExpiration() {
                return expiration;
            }
            
            public void setExpiration(long expiration) {
                this.expiration = expiration;
            }
        }
        
        public static class Cors {
            private String allowedOrigins = "*";
            private String allowedMethods = "GET,POST,PUT,DELETE,OPTIONS";
            private String allowedHeaders = "*";
            private long maxAge = 3600;
            
            // Getter 和 Setter
            public String getAllowedOrigins() {
                return allowedOrigins;
            }
            
            public void setAllowedOrigins(String allowedOrigins) {
                this.allowedOrigins = allowedOrigins;
            }
            
            public String getAllowedMethods() {
                return allowedMethods;
            }
            
            public void setAllowedMethods(String allowedMethods) {
                this.allowedMethods = allowedMethods;
            }
            
            public String getAllowedHeaders() {
                return allowedHeaders;
            }
            
            public void setAllowedHeaders(String allowedHeaders) {
                this.allowedHeaders = allowedHeaders;
            }
            
            public long getMaxAge() {
                return maxAge;
            }
            
            public void setMaxAge(long maxAge) {
                this.maxAge = maxAge;
            }
        }
        
        // Getter 和 Setter
        public Jwt getJwt() {
            return jwt;
        }
        
        public void setJwt(Jwt jwt) {
            this.jwt = jwt;
        }
        
        public Cors getCors() {
            return cors;
        }
        
        public void setCors(Cors cors) {
            this.cors = cors;
        }
    }
    
    // 主类的 Getter 和 Setter
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public String getVersion() {
        return version;
    }
    
    public void setVersion(String version) {
        this.version = version;
    }
    
    public String getDescription() {
        return description;
    }
    
    public void setDescription(String description) {
        this.description = description;
    }
    
    public String getAuthor() {
        return author;
    }
    
    public void setAuthor(String author) {
        this.author = author;
    }
    
    public Business getBusiness() {
        return business;
    }
    
    public void setBusiness(Business business) {
        this.business = business;
    }
    
    public Security getSecurity() {
        return security;
    }
    
    public void setSecurity(Security security) {
        this.security = security;
    }
}

4.2 配置监听器

// ConfigRefreshListener.java
// 配置刷新监听器
package com.example.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Set;

@Component
public class ConfigRefreshListener implements ApplicationListener<EnvironmentChangeEvent> {
    
    @Autowired
    private AppProperties appProperties;
    
    @Override
    public void onApplicationEvent(EnvironmentChangeEvent event) {
        Set<String> keys = event.getKeys();
        System.out.println("配置刷新事件触发,时间: " + LocalDateTime.now());
        System.out.println("变更的配置项: " + keys);
        
        // 处理特定配置变更
        for (String key : keys) {
            if (key.startsWith("app.business.order")) {
                System.out.println("订单业务配置发生变更: " + key);
                System.out.println("当前订单超时时间: " + appProperties.getBusiness().getOrder().getTimeout());
                System.out.println("当前重试次数: " + appProperties.getBusiness().getOrder().getRetryTimes());
            } else if (key.startsWith("app.business.user")) {
                System.out.println("用户业务配置发生变更: " + key);
                System.out.println("当前默认页面大小: " + appProperties.getBusiness().getUser().getDefaultPageSize());
                System.out.println("当前最大页面大小: " + appProperties.getBusiness().getUser().getMaxPageSize());
            } else if (key.startsWith("app.security")) {
                System.out.println("安全配置发生变更: " + key);
                System.out.println("当前JWT密钥: " + appProperties.getSecurity().getJwt().getSecret());
                System.out.println("当前JWT过期时间: " + appProperties.getSecurity().getJwt().getExpiration());
            }
        }
    }
}
// ConfigController.java
// 配置管理控制器
package com.example.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.endpoint.RefreshEndpoint;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/config")
public class ConfigController {
    
    @Autowired
    private AppProperties appProperties;
    
    @Autowired
    private RefreshEndpoint refreshEndpoint;
    
    /**
     * 获取当前配置
     */
    @GetMapping("/current")
    public ResponseEntity<AppProperties> getCurrentConfig() {
        return ResponseEntity.ok(appProperties);
    }
    
    /**
     * 手动刷新配置
     */
    @PostMapping("/refresh")
    public ResponseEntity<Map<String, Object>> refreshConfig() {
        Collection<String> keys = refreshEndpoint.refresh();
        
        Map<String, Object> result = new HashMap<>();
        result.put("refreshedKeys", keys);
        result.put("timestamp", System.currentTimeMillis());
        result.put("message", "配置刷新成功");
        
        return ResponseEntity.ok(result);
    }
    
    /**
     * 获取业务配置
     */
    @GetMapping("/business")
    public ResponseEntity<AppProperties.Business> getBusinessConfig() {
        return ResponseEntity.ok(appProperties.getBusiness());
    }
    
    /**
     * 获取安全配置
     */
    @GetMapping("/security")
    public ResponseEntity<AppProperties.Security> getSecurityConfig() {
        return ResponseEntity.ok(appProperties.getSecurity());
    }
}

5. 负载均衡配置

5.1 Ribbon 配置

# application.yml - Ribbon 负载均衡配置
user-service:
  ribbon:
    # 负载均衡策略
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule
    # 连接超时时间
    ConnectTimeout: 3000
    # 读取超时时间
    ReadTimeout: 10000
    # 重试次数
    MaxAutoRetries: 1
    # 切换实例的重试次数
    MaxAutoRetriesNextServer: 2
    # 是否对所有操作重试
    OkToRetryOnAllOperations: false
    # 服务列表刷新间隔
    ServerListRefreshInterval: 2000
    # 实例检查间隔
    NFLoadBalancerPingInterval: 30
    # 实例检查超时时间
    NFLoadBalancerPingTimeout: 5

# Feign 配置
feign:
  hystrix:
    enabled: true
  compression:
    request:
      enabled: true
      mime-types: text/xml,application/xml,application/json
      min-request-size: 2048
    response:
      enabled: true
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 10000
        loggerLevel: basic
      user-service:
        connectTimeout: 3000
        readTimeout: 8000
        loggerLevel: full

# Hystrix 配置
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 10000
      circuitBreaker:
        enabled: true
        requestVolumeThreshold: 20
        sleepWindowInMilliseconds: 5000
        errorThresholdPercentage: 50
      fallback:
        enabled: true
    UserServiceClient#getUserById(Long):
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 5000
      circuitBreaker:
        requestVolumeThreshold: 10
        errorThresholdPercentage: 30

5.2 自定义负载均衡配置

// LoadBalancerConfig.java
// 负载均衡配置类
package com.example.config;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import com.netflix.loadbalancer.RoundRobinRule;
import com.netflix.loadbalancer.WeightedResponseTimeRule;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@RibbonClient(name = "user-service", configuration = LoadBalancerConfig.class)
public class LoadBalancerConfig {
    
    @Value("${app.loadbalancer.strategy:round-robin}")
    private String strategy;
    
    @Bean
    public IRule ribbonRule() {
        switch (strategy.toLowerCase()) {
            case "random":
                return new RandomRule();
            case "weighted":
                return new WeightedResponseTimeRule();
            case "round-robin":
            default:
                return new RoundRobinRule();
        }
    }
}
// CustomLoadBalancerRule.java
// 自定义负载均衡规则
package com.example.config;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

public class CustomLoadBalancerRule extends AbstractLoadBalancerRule {
    
    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
        // 初始化配置
    }
    
    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }
    
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        }
        
        Server server = null;
        
        while (server == null) {
            if (Thread.interrupted()) {
                return null;
            }
            
            List<Server> upList = lb.getReachableServers();
            List<Server> allList = lb.getAllServers();
            
            int serverCount = allList.size();
            if (serverCount == 0) {
                return null;
            }
            
            // 自定义负载均衡逻辑:优先选择响应时间短的服务器
            if (upList.size() > 0) {
                // 简单的随机选择,实际可以根据服务器性能指标选择
                int index = ThreadLocalRandom.current().nextInt(upList.size());
                server = upList.get(index);
            }
            
            if (server == null) {
                Thread.yield();
                continue;
            }
            
            if (server.isAlive()) {
                return server;
            }
            
            server = null;
            Thread.yield();
        }
        
        return server;
    }
}

6. 服务网关集成

6.1 Gateway 配置

# gateway-application.yml - Spring Cloud Gateway 配置
spring:
  application:
    name: api-gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        namespace: public
        group: DEFAULT_GROUP
      config:
        server-addr: localhost:8848
        file-extension: yml
        namespace: public
        group: DEFAULT_GROUP
    gateway:
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/users/**
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20
                key-resolver: "#{@ipKeyResolver}"
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**
          filters:
            - StripPrefix=1
            - name: CircuitBreaker
              args:
                name: order-service-cb
                fallbackUri: forward:/fallback/orders
      default-filters:
        - name: GlobalFilter
        - name: Retry
          args:
            retries: 3
            statuses: BAD_GATEWAY,GATEWAY_TIMEOUT
            methods: GET,POST

server:
  port: 8080

management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    health:
      show-details: always

6.2 Gateway 过滤器

// GlobalAuthFilter.java
// 全局认证过滤器
package com.example.gateway.filter;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class GlobalAuthFilter implements GlobalFilter, Ordered {
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        
        String path = request.getURI().getPath();
        
        // 跳过认证的路径
        if (isSkipAuth(path)) {
            return chain.filter(exchange);
        }
        
        // 检查认证头
        String token = request.getHeaders().getFirst("Authorization");
        if (token == null || !token.startsWith("Bearer ")) {
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        
        // 验证 token(简化版本)
        if (!validateToken(token)) {
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        
        // 添加用户信息到请求头
        ServerHttpRequest modifiedRequest = request.mutate()
                .header("X-User-Id", extractUserId(token))
                .header("X-User-Name", extractUserName(token))
                .build();
        
        return chain.filter(exchange.mutate().request(modifiedRequest).build());
    }
    
    @Override
    public int getOrder() {
        return -100;
    }
    
    private boolean isSkipAuth(String path) {
        return path.startsWith("/api/auth/") || 
               path.startsWith("/api/public/") ||
               path.equals("/health") ||
               path.equals("/info");
    }
    
    private boolean validateToken(String token) {
        // 简化的 token 验证逻辑
        return token.length() > 10;
    }
    
    private String extractUserId(String token) {
        // 从 token 中提取用户 ID
        return "12345";
    }
    
    private String extractUserName(String token) {
        // 从 token 中提取用户名
        return "testuser";
    }
}
// IpKeyResolver.java
// IP 限流键解析器
package com.example.gateway.config;

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class IpKeyResolver implements KeyResolver {
    
    @Override
    public Mono<String> resolve(ServerWebExchange exchange) {
        return Mono.just(getIpAddress(exchange));
    }
    
    private String getIpAddress(ServerWebExchange exchange) {
        String xForwardedFor = exchange.getRequest().getHeaders().getFirst("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
            return xForwardedFor.split(",")[0].trim();
        }
        
        String xRealIp = exchange.getRequest().getHeaders().getFirst("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty()) {
            return xRealIp;
        }
        
        return exchange.getRequest().getRemoteAddress() != null ?
                exchange.getRequest().getRemoteAddress().getAddress().getHostAddress() : "unknown";
    }
}

7. 测试与验证

7.1 单元测试

// UserServiceTest.java
// 用户服务测试
package com.example.userservice.service;

import com.example.userservice.entity.User;
import com.example.userservice.service.impl.UserServiceImpl;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
@TestPropertySource(properties = {
    "spring.cloud.nacos.discovery.server-addr=localhost:8848",
    "spring.cloud.nacos.config.server-addr=localhost:8848"
})
class UserServiceTest {
    
    private UserServiceImpl userService;
    
    @BeforeEach
    void setUp() {
        userService = new UserServiceImpl();
    }
    
    @Test
    void testCreateUser() {
        User user = new User();
        user.setUsername("testuser");
        user.setEmail("test@example.com");
        user.setPhone("13800138000");
        
        User createdUser = userService.createUser(user);
        
        assertNotNull(createdUser);
        assertNotNull(createdUser.getId());
        assertEquals("testuser", createdUser.getUsername());
        assertEquals("test@example.com", createdUser.getEmail());
        assertNotNull(createdUser.getCreateTime());
    }
    
    @Test
    void testGetUserById() {
        // 先创建用户
        User user = new User();
        user.setUsername("testuser2");
        user.setEmail("test2@example.com");
        User createdUser = userService.createUser(user);
        
        // 查询用户
        User foundUser = userService.getUserById(createdUser.getId());
        
        assertNotNull(foundUser);
        assertEquals(createdUser.getId(), foundUser.getId());
        assertEquals("testuser2", foundUser.getUsername());
    }
    
    @Test
    void testGetUserByIdNotFound() {
        User user = userService.getUserById(999L);
        assertNull(user);
    }
    
    @Test
    void testUpdateUser() {
        // 先创建用户
        User user = new User();
        user.setUsername("testuser3");
        user.setEmail("test3@example.com");
        User createdUser = userService.createUser(user);
        
        // 更新用户
        createdUser.setEmail("updated@example.com");
        User updatedUser = userService.updateUser(createdUser);
        
        assertNotNull(updatedUser);
        assertEquals("updated@example.com", updatedUser.getEmail());
        assertNotNull(updatedUser.getUpdateTime());
    }
    
    @Test
    void testDeleteUser() {
        // 先创建用户
        User user = new User();
        user.setUsername("testuser4");
        user.setEmail("test4@example.com");
        User createdUser = userService.createUser(user);
        
        // 删除用户
        boolean deleted = userService.deleteUser(createdUser.getId());
        assertTrue(deleted);
        
        // 验证用户已删除
        User deletedUser = userService.getUserById(createdUser.getId());
        assertNull(deletedUser);
    }
}

7.2 集成测试

// OrderServiceIntegrationTest.java
// 订单服务集成测试
package com.example.orderservice.integration;

import com.example.orderservice.entity.Order;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureWebMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureWebMvc
@TestPropertySource(properties = {
    "spring.cloud.nacos.discovery.server-addr=localhost:8848",
    "spring.cloud.nacos.config.server-addr=localhost:8848"
})
class OrderServiceIntegrationTest {
    
    @Autowired
    private WebApplicationContext webApplicationContext;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    private MockMvc mockMvc;
    
    @Test
    void testCreateOrder() throws Exception {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
        
        Order order = new Order();
        order.setUserId(1L);
        order.setProductName("测试商品");
        order.setQuantity(2);
        order.setPrice(99.99);
        order.setStatus(0);
        
        mockMvc.perform(post("/orders")
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(order)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id").exists())
                .andExpect(jsonPath("$.userId").value(1L))
                .andExpect(jsonPath("$.productName").value("测试商品"))
                .andExpect(jsonPath("$.quantity").value(2))
                .andExpect(jsonPath("$.price").value(99.99));
    }
    
    @Test
    void testGetOrderById() throws Exception {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
        
        mockMvc.perform(get("/orders/1"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id").value(1L));
    }
    
    @Test
    void testGetServiceInfo() throws Exception {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
        
        mockMvc.perform(get("/orders/info"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.serviceName").exists())
                .andExpect(jsonPath("$.serverPort").exists())
                .andExpect(jsonPath("$.timestamp").exists());
    }
    
    @Test
    void testHealthCheck() throws Exception {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
        
        mockMvc.perform(get("/orders/health"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.status").value("UP"))
                .andExpect(jsonPath("$.serviceName").exists());
    }
}

7.3 性能测试脚本

#!/bin/bash
# performance-test.sh
# 性能测试脚本

echo "开始性能测试..."

# 测试用户服务
echo "测试用户服务性能..."
ab -n 1000 -c 10 http://localhost:8081/users/info

# 测试订单服务
echo "测试订单服务性能..."
ab -n 1000 -c 10 http://localhost:8082/orders/info

# 测试网关
echo "测试网关性能..."
ab -n 1000 -c 10 http://localhost:8080/api/users/info
ab -n 1000 -c 10 http://localhost:8080/api/orders/info

# 测试配置刷新
echo "测试配置刷新..."
for i in {1..10}; do
    curl -X POST http://localhost:8081/config/refresh
    curl -X POST http://localhost:8082/config/refresh
    sleep 1
done

echo "性能测试完成!"

8. 监控与运维

8.1 健康检查配置

# application.yml - 健康检查配置
management:
  endpoints:
    web:
      exposure:
        include: "health,info,metrics,prometheus,nacos-discovery,nacos-config"
      base-path: /actuator
  endpoint:
    health:
      show-details: always
      show-components: always
    info:
      enabled: true
    metrics:
      enabled: true
  health:
    nacos:
      enabled: true
    diskspace:
      enabled: true
    db:
      enabled: true
  metrics:
    export:
      prometheus:
        enabled: true
    distribution:
      percentiles-histogram:
        http.server.requests: true
      percentiles:
        http.server.requests: 0.5, 0.9, 0.95, 0.99

info:
  app:
    name: ${spring.application.name}
    version: 1.0.0
    description: Spring Cloud Nacos 集成示例
  build:
    time: ${maven.build.timestamp}
  git:
    branch: ${git.branch}
    commit: ${git.commit.id}

8.2 日志配置

<!-- logback-spring.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <springProfile name="!prod">
        <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
        <include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
        
        <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>logs/${spring.application.name}.log</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>logs/${spring.application.name}.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>100MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
                <maxHistory>30</maxHistory>
            </rollingPolicy>
            <encoder>
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{traceId}] %logger{36} - %msg%n</pattern>
            </encoder>
        </appender>
        
        <root level="INFO">
            <appender-ref ref="CONSOLE"/>
            <appender-ref ref="FILE"/>
        </root>
        
        <logger name="com.example" level="DEBUG"/>
        <logger name="com.alibaba.nacos" level="INFO"/>
        <logger name="org.springframework.cloud" level="DEBUG"/>
    </springProfile>
    
    <springProfile name="prod">
        <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>logs/${spring.application.name}.log</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>logs/${spring.application.name}.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>500MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
                <maxHistory>60</maxHistory>
            </rollingPolicy>
            <encoder>
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{traceId}] %logger{36} - %msg%n</pattern>
            </encoder>
        </appender>
        
        <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>ERROR</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
            <file>logs/${spring.application.name}-error.log</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>logs/${spring.application.name}-error.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>100MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
                <maxHistory>90</maxHistory>
            </rollingPolicy>
            <encoder>
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{traceId}] %logger{36} - %msg%n</pattern>
            </encoder>
        </appender>
        
        <root level="INFO">
            <appender-ref ref="FILE"/>
            <appender-ref ref="ERROR_FILE"/>
        </root>
        
        <logger name="com.example" level="INFO"/>
        <logger name="com.alibaba.nacos" level="WARN"/>
        <logger name="org.springframework.cloud" level="WARN"/>
    </springProfile>
</configuration>

9. 核心要点

9.1 架构设计

  • 服务拆分: 按业务领域拆分服务,保持服务的单一职责
  • 配置管理: 使用 Nacos 统一管理配置,支持多环境和热更新
  • 服务发现: 利用 Nacos 实现服务的自动注册与发现
  • 负载均衡: 配置合适的负载均衡策略,提高系统可用性
  • 网关集成: 使用 Spring Cloud Gateway 统一入口和路由

9.2 最佳实践

  • 配置分层: 按环境、应用、模块分层管理配置
  • 健康检查: 配置完善的健康检查机制
  • 监控告警: 集成 Prometheus 和 Grafana 监控
  • 日志管理: 统一日志格式和收集策略
  • 安全防护: 实现认证、授权和限流机制

9.3 性能优化

  • 连接池优化: 合理配置 HTTP 连接池参数
  • 缓存策略: 使用本地缓存和分布式缓存
  • 异步处理: 使用异步调用提高响应速度
  • 批量操作: 减少网络调用次数
  • 资源隔离: 使用线程池隔离不同业务

10. 下一步学习

  1. Spring Cloud Alibaba Sentinel: 学习熔断降级和流量控制
  2. Spring Cloud Alibaba Seata: 学习分布式事务处理
  3. Spring Cloud Sleuth: 学习分布式链路追踪
  4. Spring Cloud Stream: 学习消息驱动的微服务
  5. Kubernetes 部署: 学习容器化部署和编排

通过本教程,你已经掌握了 Nacos 与 Spring Cloud 的集成方法,包括服务注册发现、配置管理、负载均衡、网关集成等核心功能。继续深入学习相关技术,构建更加完善的微服务架构。