CC 咖啡猫的工作空间 Coding Space

Spring Cloud 组件与配置实践

Spring Cloud 是微服务开发的标准框架,提供了一套开箱即用的分布式系统解决方案。本文档从实战角度出发,讲解 Spring Cloud 核心组件的使用与配置。


一、Spring Cloud 组件全景

1.1 Spring Cloud 全家桶

                    ┌─────────────┐
                    │  Gateway    │  ← 网关(统一入口、路由转发、限流)
                    └──────┬──────┘
                           │
              ┌────────────┼────────────┐
              ▼            ▼            ▼
        ┌──────────┐ ┌──────────┐ ┌──────────┐
        │ Service  │ │ Service  │ │ Service  │  ← 微服务集群
        │    A     │ │    B     │ │    C     │
        └────┬─────┘ └────┬─────┘ └────┬─────┘
             │            │            │
             └────────────┼────────────┘
                          │
              ┌───────────┼───────────┐
              ▼           ▼           ▼
        ┌──────────┐ ┌──────────┐ ┌──────────┐
        │  Nacos   │ │ Sentinel │ │ Sleuth   │  ← 基础设施
        │ 注册配置  │ │ 熔断限流  │ │ 链路追踪  │
        └──────────┘ └──────────┘ └──────────┘

1.2 组件职责速查

组件 职责 一句话
Nacos 服务注册发现 + 配置中心 服务在哪、配置是什么
OpenFeign 声明式 HTTP 客户端 写接口就能调远程服务
Spring Cloud LoadBalancer 客户端负载均衡 自动选一个健康的实例
Gateway API 网关 统一入口、路由、鉴权、限流
Sentinel 流量控制 + 熔断降级 保护自己不被流量打垮
Sleuth + Zipkin 分布式链路追踪 一个请求经过哪些服务

1.3 版本对应关系(Spring Cloud Alibaba)

Spring Cloud Spring Cloud Alibaba Spring Boot Nacos
2022.0.x 2022.0.0.x 3.0.x 2.x
2021.0.x 2021.0.5.x 2.6.x / 2.7.x 2.x
2020.0.x 2021.1 2.4.x / 2.5.x 1.4.x
Hoxton.SR12 2.2.10 2.3.x 1.4.x

二、服务注册与发现(Nacos)

2.1 引入依赖

<!-- Nacos 服务发现 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

2.2 基本配置

# bootstrap.yml(Spring Cloud 2.4+ 用 application.yml)
spring:
  application:
    name: order-service        # 服务名,注册到 Nacos 的名称
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848    # Nacos 服务地址
        namespace: dev                  # 命名空间 ID(不是名称)
        group: DEFAULT_GROUP            # 分组
        cluster-name: HZ               # 集群名称(用于就近路由)
        ephemeral: true                 # true=临时实例(AP模式),false=持久实例(CP模式)

2.3 启动类注解

@SpringBootApplication
@EnableDiscoveryClient  // 开启服务发现(Spring Cloud 2.x 可省略,自动启用)
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }
}

2.4 验证服务注册

启动后访问 Nacos 控制台 http://127.0.0.1:8848/nacos,在"服务管理 → 服务列表"中能看到 order-service

# 命令行验证
curl http://127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=order-service

2.5 服务分级(机房就近路由)

# 订单服务(杭州集群)
spring:
  cloud:
    nacos:
      discovery:
        cluster-name: HZ   # 杭州集群

# 用户服务(北京集群)
spring:
  cloud:
    nacos:
      discovery:
        cluster-name: BJ   # 北京集群
// Ribbon 配置:优先调用同集群的服务
// application.yml 全局配置
spring:
  cloud:
    nacos:
      discovery:
        cluster-name: HZ

# 负载均衡策略
order-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule

三、远程调用(OpenFeign + LoadBalancer)

3.1 引入依赖

<!-- OpenFeign -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

<!-- Spring Cloud LoadBalancer(Spring Cloud 2.x 默认,替代 Ribbon) -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

3.2 声明 Feign 客户端

// 1. 定义 Feign 接口
//    name = 目标服务在 Nacos 中的服务名
@FeignClient(name = "user-service",              // Nacos 中的服务名
             path = "/users",                    // 公共路径前缀
             fallbackFactory = UserFeignFallback.class)  // 降级处理
public interface UserFeignClient {

    @GetMapping("/{id}")
    // @PathVariable 必须显式指定 value
    Result<UserVO> getUserById(@PathVariable("id") Long id);

    @GetMapping("/batch")
    Result<List<UserVO>> getUserByIds(@RequestParam("ids") List<Long> ids);

    @PostMapping
    Result<Void> createUser(@RequestBody UserDTO user);
}

// 2. 服务降级工厂(用于 Sentinel 熔断降级)
@Component
public class UserFeignFallback implements FallbackFactory<UserFeignClient> {

    @Override
    public UserFeignClient create(Throwable cause) {
        log.error("调用 user-service 失败", cause);
        return new UserFeignClient() {
            @Override
            public Result<UserVO> getUserById(Long id) {
                return Result.error("用户服务暂时不可用");
            }
            @Override
            public Result<List<UserVO>> getUserByIds(List<Long> ids) {
                return Result.error("用户服务暂时不可用");
            }
            @Override
            public Result<Void> createUser(UserDTO user) {
                return Result.error("用户服务暂时不可用");
            }
        };
    }
}

3.3 启用 Feign

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.example.feign")  // 扫描 Feign 接口
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }
}

3.4 调用方式

@RestController
@RequestMapping("/orders")
public class OrderController {

    @Autowired
    private UserFeignClient userFeignClient;

    @GetMapping("/{id}")
    public Result<OrderVO> getOrder(@PathVariable Long id) {
        // 1. 查订单
        Order order = orderService.getById(id);

        // 2. 通过 Feign 调用用户服务,获取用户信息
        //    Feign 内部:从 Nacos 获取 user-service 的实例列表
        //              → LoadBalancer 选一个实例
        //              → 发送 HTTP 请求
        Result<UserVO> userResult = userFeignClient.getUserById(order.getUserId());

        // 3. 组装返回
        OrderVO vo = new OrderVO();
        vo.setOrder(order);
        if (userResult.isSuccess()) {
            vo.setUser(userResult.getData());
        }
        return Result.ok(vo);
    }
}

3.5 Feign 配置优化

spring:
  cloud:
    openfeign:
      client:
        config:
          default:                    # 全局默认配置
            connect-timeout: 3000     # 连接超时(毫秒)
            read-timeout: 5000        # 读取超时(毫秒)
            logger-level: BASIC       # 日志级别:NONE / BASIC / HEADERS / FULL
          user-service:               # 针对特定服务的配置(覆盖全局)
            connect-timeout: 2000
            read-timeout: 4000
      compression:
        request:
          enabled: true               # 开启请求 Gzip 压缩
          min-request-size: 2048      # 超过 2KB 才压缩
        response:
          enabled: true               # 开启响应 Gzip 解压
// Feign 拦截器:统一传递请求头(如 Token)
@Component
public class FeignRequestInterceptor implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate template) {
        // 从当前请求上下文获取 Token,透传给下游服务
        String token = RequestContextHolder.getRequestAttributes()
            .getHeader("Authorization");
        if (token != null) {
            template.header("Authorization", token);
        }
    }
}

3.6 Feign 日志配置

logging:
  level:
    com.example.feign.UserFeignClient: DEBUG  # 打印 Feign 请求详情

3.7 Feign 常见问题

问题1:GET 请求传对象数组

// ❌ 错误:GET 请求不能传 body
@GetMapping("/users")
Result<List<UserVO>> getUsers(@RequestBody List<Long> ids);

// ✅ 正确:拆分为 @RequestParam
@GetMapping("/users")
Result<List<UserVO>> getUsers(@RequestParam("ids") List<Long> ids);

问题2:Feign 调用超时

# 默认超时 1 秒太短,必须放大
spring:
  cloud:
    openfeign:
      client:
        config:
          default:
            read-timeout: 10000   # 放大到 10 秒

问题3:Feign 调用时丢失请求头(Token 透传)

// 见上方 FeignRequestInterceptor 示例
// 本质:Feign 发起新请求时不会自动携带原始请求的 Header
// 解决:Feign 拦截器中手动设置

四、API 网关(Spring Cloud Gateway)

4.1 引入依赖

<!-- Gateway 依赖(不包含 spring-boot-starter-web,两者冲突) -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

<!-- 需要 Nacos 服务发现,结合使用 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

4.2 基本路由配置

spring:
  cloud:
    gateway:
      routes:
        # 路由1:订单服务
        - id: order-service-route                  # 路由 ID(唯一)
          uri: lb://order-service                   # lb:// = 通过负载均衡转发
          predicates:
            - Path=/api/orders/**                  # 匹配 /api/orders/** 的请求
          filters:
            - StripPrefix=1                        # 去掉第一段路径 /api,转发到 /orders/**

        # 路由2:用户服务
        - id: user-service-route
          uri: lb://user-service
          predicates:
            - Path=/api/users/**
          filters:
            - StripPrefix=1

        # 路由3:后台管理(需要鉴权)
        - id: admin-service-route
          uri: lb://admin-service
          predicates:
            - Path=/api/admin/**
          filters:
            - StripPrefix=1
            - AuthFilter                         # 自定义鉴权过滤器

      # 全局默认过滤器
      default-filters:
        - AddRequestHeader=X-Request-Id, ${random.uuid}  # 添加请求追踪 ID

4.3 断言(Predicate)常用写法

断言 说明 示例
Path=/api/** 路径匹配 匹配 /api/users
Header=X-Request-Id, \d+ 必须包含某请求头 Header 中有数字
Method=GET,POST 请求方法 只允许 GET/POST
Query=name, zh.* 必须有某查询参数 ?name=zhang
Before=2025-01-01T00:00:00+08:00[Asia/Shanghai] 指定时间之前 活动时段控制
Host=**.example.com 根据域名路由 多域名场景

4.4 过滤器(Filter)实战

内置过滤器

filters:
  - StripPrefix=1                     # 去掉路径前缀
  - AddRequestHeader=X-Header, value  # 添加请求头
  - AddResponseHeader=X-Resp, value   # 添加响应头
  - RewritePath=/api/(?<seg>.*), /$\{seg}  # 路径重写
  - PrefixPath=/api                   # 添加路径前缀
  - RequestRateLimiter=..., redis-rate-limiter  # 限流
  - Retry=3                           # 请求失败重试 3 次
  - CircuitBreaker=..., ...           # 断路器

自定义全局过滤器:鉴权

@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String path = exchange.getRequest().getURI().getPath();

        // 1. 白名单路径放行
        if (path.startsWith("/api/public/") || path.startsWith("/api/auth/login")) {
            return chain.filter(exchange);
        }

        // 2. 获取 Token
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        if (token == null || token.isEmpty()) {
            // 返回 401
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        // 3. 验证 Token(简化示例)
        try {
            // 解析 Token 获取用户 ID,存入 Header 传递给下游
            Long userId = JwtUtil.parseToken(token);
            exchange.getRequest().mutate()
                .header("X-User-Id", userId.toString())
                .build();
        } catch (Exception e) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        // 4. 放行
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -1;  // 值越小越先执行
    }
}

4.5 跨域配置(CORS)

spring:
  cloud:
    gateway:
      globalcors:
        corsConfigurations:
          '[/**]':
            allowedOrigins: "http://localhost:3000"   # 允许的前端地址
            allowedMethods:
              - GET
              - POST
              - PUT
              - DELETE
            allowedHeaders: "*"
            allowCredentials: true
            maxAge: 3600                              # 预检请求缓存时间

五、配置中心(Nacos Config)

5.1 引入依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

5.2 基本配置

# bootstrap.yml(优先于 application.yml 加载)
spring:
  application:
    name: order-service
  cloud:
    nacos:
      # 服务发现配置
      discovery:
        server-addr: 127.0.0.1:8848
        namespace: dev
      # 配置中心配置
      config:
        server-addr: 127.0.0.1:8848
        namespace: dev                       # 命名空间 ID
        group: DEFAULT_GROUP                 # 分组
        file-extension: yaml                 # 配置文件格式
        refresh-enabled: true                # 开启自动刷新

  # 多环境配置
  profiles:
    active: dev

5.3 Nacos 配置文件命名规则

${prefix}-${spring.profiles.active}.${file-extension}

示例:
  order-service.yaml          → 默认配置
  order-service-dev.yaml      → dev 环境配置
  order-service-prod.yaml     → prod 环境配置

5.4 动态刷新配置

// 方式1:@Value(需要 @RefreshScope)
@RestController
@RefreshScope   // 关键:配置变更时自动刷新
public class OrderController {

    @Value("${order.page-size:10}")   // 默认值 10
    private int pageSize;

    @Value("${order.welcome-msg:欢迎}")
    private String welcomeMsg;

    @GetMapping("/config")
    public Map<String, Object> getConfig() {
        return Map.of("pageSize", pageSize, "welcomeMsg", welcomeMsg);
    }
}

// 方式2:@ConfigurationProperties(推荐,类型安全,无需 @RefreshScope)
@Component
@ConfigurationProperties(prefix = "order")
@RefreshScope
@Data
public class OrderProperties {
    private int pageSize = 10;
    private String welcomeMsg = "欢迎";
    private Map<String, String> cache = new HashMap<>();  // order.cache[key]=value
}

// 使用
@Autowired
private OrderProperties orderProperties;

5.5 多配置优先级

应用本身配置 > 扩展配置 > 共享配置

        优先级从高到低:
        application-profile.yml              (应用-环境配置)
            ↓
        application.yml                      (应用公共配置)
            ↓
        extension-config[N].yml              (扩展配置)
            ↓
        shared-config[N].yml                 (共享配置)

5.6 共享配置实践

# bootstrap.yml
spring:
  cloud:
    nacos:
      config:
        # 共享配置:多个服务共享同一份配置
        shared-configs:
          - data-id: common-datasource.yaml     # 公共数据源配置
            group: DEFAULT_GROUP
            refresh: true
          - data-id: common-redis.yaml          # 公共 Redis 配置
            group: DEFAULT_GROUP
            refresh: true

        # 扩展配置:按需加载
        extension-configs:
          - data-id: order-extra.yaml           # 订单服务专属扩展配置
            group: DEFAULT_GROUP
            refresh: true

六、熔断降级(Sentinel)

6.1 引入依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

<!-- Sentinel 控制台(可视化规则管理) -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-transport-simple-http</artifactId>
</dependency>

6.2 基本配置

spring:
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080      # Sentinel 控制台地址
        port: 8719                      # 本机与控制台通信端口
      eager: true                       # 启动时立即初始化(false=懒加载)
      datasource:
        # 规则持久化到 Nacos
        ds1:
          nacos:
            server-addr: 127.0.0.1:8848
            data-id: order-service-sentinel-rules
            group-id: DEFAULT_GROUP
            data-type: json
            rule-type: flow

6.3 流量控制(限流)

// @SentinelResource 定义资源,配置限流规则
@RestController
public class OrderController {

    @GetMapping("/orders/{id}")
    @SentinelResource(
        value = "getOrder",                  // 资源名称
        blockHandler = "getOrderBlockHandler", // 被限流时的降级方法
        fallback = "getOrderFallback"         // 业务异常时的降级方法
    )
    public Result<OrderVO> getOrder(@PathVariable Long id) {
        // 业务逻辑
        return Result.ok(orderService.getById(id));
    }

    // 被限流时的处理方法(参数必须包含原方法参数 + BlockException)
    public Result<OrderVO> getOrderBlockHandler(Long id, BlockException e) {
        return Result.error("请求人数太多,请稍后再试");
    }

    // 业务异常时的降级方法(参数必须包含原方法参数 + Throwable)
    public Result<OrderVO> getOrderFallback(Long id, Throwable e) {
        log.error("查询订单失败,orderId: {}", id, e);
        return Result.error("服务暂不可用");
    }
}

6.4 Sentinel 控制台规则

规则类型 说明 示例
流量控制(Flow) 超过阈值时限流 QPS > 100 时限流
降级(Degrade) 响应慢/异常率高时降级 RT > 200ms 时熔断
热点参数(ParamFlow) 针对特定参数限流 热点商品 ID 限流
系统规则(System) 系统级别保护 CPU > 80% 时限流
授权规则(Auth) 黑白名单控制 某 IP 禁止访问

6.5 代码中定义规则(替代控制台)

@Component
public class SentinelRuleConfig {

    @PostConstruct
    public void initFlowRules() {
        List<FlowRule> rules = new ArrayList<>();

        // 规则1:getOrder 接口 QPS 限制
        FlowRule rule1 = new FlowRule();
        rule1.setResource("getOrder");       // 资源名
        rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);  // QPS 模式
        rule1.setCount(100);                 // QPS 上限
        rules.add(rule1);

        // 规则2:createOrder 接口并发线程数限制
        FlowRule rule2 = new FlowRule();
        rule2.setResource("createOrder");
        rule2.setGrade(RuleConstant.FLOW_GRADE_THREAD);  // 并发线程模式
        rule2.setCount(20);                  // 最大并发线程数
        rules.add(rule2);

        FlowRuleManager.loadRules(rules);
    }
}

6.6 Sentinel 与 OpenFeign 集成

# 开启 Sentinel 对 Feign 的支持
feign:
  sentinel:
    enabled: true    # 开启后 fallbackFactory 才生效
// Feign 接口中指定 fallbackFactory
@FeignClient(
    name = "user-service",
    fallbackFactory = UserFeignFallback.class  // Sentinel 限流后走这里
)
public interface UserFeignClient {
    @GetMapping("/users/{id}")
    Result<UserVO> getUserById(@PathVariable("id") Long id);
}

6.7 对比:Sentinel vs Hystrix

维度 Sentinel Hystrix
维护状态 活跃维护(阿里) 已停更(Netflix)
隔离策略 信号量隔离 线程池隔离
熔断降级 支持(慢调用/异常) 支持(超时/异常)
限流 支持(QPS/线程) 不支持
控制台 功能完善 基础
规则动态生效 支持 不支持
选择 ✅ 推荐 ❌ 已停更

七、链路追踪(Sleuth + Zipkin 或 Micrometer Tracing)

7.1 引入依赖(Spring Cloud 2.x 传统方案)

<!-- Sleuth:生成 TraceId + SpanId -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>

<!-- Zipkin:上报链路数据到 Zipkin Server -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>

7.2 配置

spring:
  sleuth:
    sampler:
      probability: 0.1         # 采样率 10%(生产环境避免全部采样)
  zipkin:
    base-url: http://127.0.0.1:9411   # Zipkin Server 地址
    sender:
      type: web                          # 通过 HTTP 上报

7.3 Spring Boot 3.x 替代方案(Micrometer Tracing)

Spring Cloud 2022.x+ 已弃用 Sleuth:

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-tracing-reporter-brave-zipkin</artifactId>
</dependency>
management:
  tracing:
    sampling:
      probability: 0.1       # 采样率 10%
  zipkin:
    tracing:
      endpoint: http://127.0.0.1:9411/api/v2/spans

八、完整项目配置示例

8.1 父工程 pom.xml

<properties>
    <java.version>17</java.version>
    <spring-boot.version>3.2.0</spring-boot.version>
    <spring-cloud.version>2023.0.0</spring-cloud.version>
    <spring-cloud-alibaba.version>2023.0.1.0</spring-cloud-alibaba.version>
</properties>

<dependencyManagement>
    <dependencies>
        <!-- Spring Boot -->
        <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 -->
        <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 -->
        <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>

8.2 微服务模块 pom.xml

<dependencies>
    <!-- Nacos 服务发现 -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>

    <!-- Nacos 配置中心 -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>

    <!-- OpenFeign -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>

    <!-- LoadBalancer -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    </dependency>

    <!-- Sentinel -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
</dependencies>

8.3 微服务 bootstrap.yml(完整配置)

# bootstrap.yml
spring:
  application:
    name: order-service

  # 指定环境
  profiles:
    active: ${SPRING_PROFILES_ACTIVE:dev}

  cloud:
    # Nacos 服务发现 + 配置中心
    nacos:
      discovery:
        server-addr: ${NACOS_ADDR:127.0.0.1:8848}
        namespace: ${NACOS_NAMESPACE:dev}
        group: DEFAULT_GROUP
      config:
        server-addr: ${NACOS_ADDR:127.0.0.1:8848}
        namespace: ${NACOS_NAMESPACE:dev}
        group: DEFAULT_GROUP
        file-extension: yaml
        refresh-enabled: true
        shared-configs:                                # 共享配置
          - data-id: common-log.yaml
            group: DEFAULT_GROUP
            refresh: true
          - data-id: common-datasource.yaml
            group: DEFAULT_GROUP
            refresh: true

    # Sentinel
    sentinel:
      transport:
        dashboard: ${SENTINEL_DASHBOARD:127.0.0.1:8080}
        port: 8719
      eager: true                                      # 立即初始化
      datasource:
        flow:
          nacos:
            server-addr: ${NACOS_ADDR:127.0.0.1:8848}
            data-id: order-service-flow-rules
            group-id: DEFAULT_GROUP
            rule-type: flow

    # OpenFeign 全局超时
    openfeign:
      client:
        config:
          default:
            connect-timeout: 5000
            read-timeout: 10000
      compression:
        request:
          enabled: true
        response:
          enabled: true

# 日志级别
logging:
  level:
    com.example: DEBUG
    com.alibaba.nacos.client: WARN   # Nacos 客户端日志不要太多

8.4 启动类完整注解

@SpringBootApplication
@EnableDiscoveryClient                            // 服务发现
@EnableFeignClients(basePackages = "com.example.feign")  // Feign
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }
}

九、常见问题排查

9.1 服务注册上了但 Feign 调用报 404

可能原因

  1. 目标服务的 context-path 不一致 → 检查 server.servlet.context-path
  2. Feign 接口路径写错了 → 检查 @RequestMapping@GetMapping 路径
  3. 目标服务有多个实例,但只有一个对外 → 检查健康状态
# 排查步骤
# 1. 确认服务已注册
curl http://nacos:8848/nacos/v1/ns/instance/list?serviceName=user-service

# 2. 手动调用验证
curl http://user-service:8080/users/1

# 3. Feign 开启 FULL 日志
logging:
  level:
    com.example.feign: FULL

9.2 配置刷新不生效

# 排查步骤
# 1. 确认 Nacos 控制台配置确实改了
# 2. 确认类上有 @RefreshScope
# 3. 确认不是 static 字段
# 4. 开启 Nacos 日志
logging.level.com.alibaba.nacos.client.config: DEBUG
# 5. 日志中查找 "received config change notification"

9.3 Gateway 路由不生效

# 开启 Gateway 路由日志
logging:
  level:
    org.springframework.cloud.gateway: TRACE
    org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping: DEBUG

9.4 Sentinel 规则不生效

# 1. 确认 Sentinel 控制台能看到应用
# 2. 确认应用中对应资源有访问流量
# 3. 确认规则类型和数据正确
# 4. 检查 Nacos 持久化配置是否同步

十、总结

10.1 Spring Cloud 组件选型

组件 推荐 已弃用
注册中心 Nacos Eureka(停更)
配置中心 Nacos Spring Cloud Config(不支持推送)
远程调用 OpenFeign RestTemplate
负载均衡 Spring Cloud LoadBalancer Ribbon(停更)
网关 Gateway Zuul(停更)
熔断限流 Sentinel Hystrix(停更)
链路追踪 Micrometer Tracing Sleuth(3.x 弃用)

10.2 版本选择速查

Spring Boot 2.x → Spring Cloud 2021.0.x → Spring Cloud Alibaba 2021.0.5.x
Spring Boot 3.x → Spring Cloud 2022.0.x+ → Spring Cloud Alibaba 2022.0.x+