Spring Cloud

技术栈
后端框架
javaspring微服务分布式服务发现配置中心

概览

Spring Cloud

Spring Cloud 是基于 Spring Boot 的分布式系统/微服务架构一站式解决方案。

是什么

Spring Cloud 提供了一套工具集,用于快速构建分布式系统中的常见模式:配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、分布式会话等。

解决什么问题

  • 服务注册与发现:服务动态上下线,消费者自动发现提供者
  • 配置统一管理:集中化配置,动态刷新
  • 负载均衡:客户端负载均衡
  • 熔断降级:防止级联故障
  • API 网关:统一入口、路由、限流、鉴权
  • 分布式链路追踪:可视化调用链

关键组件

组件 用途
Spring Cloud Netflix Eureka 服务注册与发现(已进入维护模式)
Spring Cloud Gateway API 网关
Spring Cloud Config 配置中心
Spring Cloud OpenFeign 声明式 HTTP 客户端
Spring Cloud Circuit Breaker 熔断器(Resilience4j)
Spring Cloud Sleuth 链路追踪(已迁移至 Micrometer Tracing)
Spring Cloud LoadBalancer 负载均衡

安装

Spring Cloud 安装指南

1. 环境准备

前置条件

  • JDK 17+(Spring Cloud 2023.x 基于 Spring Boot 3.x)
  • Maven 3.6+ 或 Gradle 7+

版本对应关系

Spring Cloud Release Spring Boot 版本
2023.0.x (Leyton) 3.2.x
2022.0.x (Kilburn) 3.0.x ~ 3.1.x
2021.0.x (Jubilee) 2.6.x ~ 2.7.x
2020.0.x (Ilford) 2.4.x ~ 2.5.x

2. 安装步骤

Maven BOM 统一版本管理

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>2023.0.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

按需引入组件

<!-- 服务注册与发现:Eureka Client -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

<!-- API 网关:Spring Cloud Gateway -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

<!-- 声明式 HTTP 客户端:OpenFeign -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

<!-- 熔断器:Resilience4j -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>

<!-- 配置中心:Config Client -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>

<!-- 负载均衡 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

3. 常见安装问题

Q: Gateway 与 Spring MVC 冲突?

Gateway 基于 WebFlux(Netty),不要同时引入 spring-boot-starter-web

Q: Eureka Server 报错?

确保配置:

eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

Q: 版本不兼容?

始终使用 Spring Cloud BOM 管理版本,不要手动指定子组件版本。

示例

Spring Cloud 微服务调用链示例

目标

构建完整微服务调用链:Gateway 路由 → 服务发现 → Feign 调用 → Resilience4j 熔断。

架构

Client → Gateway (8080) → User Service (8081)
                        → Order Service (8082)
                              └── Feign → User Service

完整代码

1. Eureka Server(注册中心)

// pom: spring-cloud-starter-netflix-eureka-server
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}
# application.properties
server.port=8761
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

2. User Service(服务提供者 8081)

@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication { ... }

@RestController
@RequestMapping("/users")
public class UserController {
    @GetMapping("/{id}")
    public Map<String, Object> getUser(@PathVariable Long id) {
        return Map.of("id", id, "name", "Alice", "email", "alice@example.com");
    }
}
spring.application.name=user-service
server.port=8081
eureka.client.service-url.defaultZone=http://localhost:8761/eureka

3. Order Service(服务消费者 8082)

// Feign 客户端
@FeignClient(name = "user-service", fallbackFactory = UserClientFallback.class)
public interface UserClient {
    @GetMapping("/users/{id}")
    Map<String, Object> getUser(@PathVariable Long id);
}

@Component
public class UserClientFallback implements FallbackFactory<UserClient> {
    @Override
    public UserClient create(Throwable cause) {
        return id -> Map.of("id", id, "error", "User service unavailable");
    }
}

// Controller
@RestController
@RequestMapping("/orders")
public class OrderController {
    @Autowired
    private UserClient userClient;

    @GetMapping("/{id}")
    public Map<String, Object> getOrder(@PathVariable Long id) {
        Map<String, Object> user = userClient.getUser(1L);
        return Map.of(
            "orderId", id,
            "product", "MacBook Pro",
            "user", user
        );
    }
}
spring.application.name=order-service
server.port=8082
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
# Resilience4j 熔断配置
resilience4j.circuitbreaker.instances.user-service.sliding-window-size=10
resilience4j.circuitbreaker.instances.user-service.failure-rate-threshold=50
resilience4j.circuitbreaker.instances.user-service.wait-duration-in-open-state=30s
// 启用 Feign + CircuitBreaker
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderServiceApplication { ... }

4. API Gateway(网关 8080)

@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication { ... }
# application.yml
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/users/**
          filters:
            - StripPrefix=1
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**
          filters:
            - StripPrefix=1
      default-filters:
        - name: RequestRateLimiter
          args:
            redis-rate-limiter.replenishRate: 10
            redis-rate-limiter.burstCapacity: 20

server:
  port: 8080

运行步骤

# 按顺序启动
# 1. Eureka Server
./mvnw spring-boot:run -pl eureka-server

# 2. User Service
./mvnw spring-boot:run -pl user-service

# 3. Order Service
./mvnw spring-boot:run -pl order-service

# 4. Gateway
./mvnw spring-boot:run -pl gateway

测试

# 通过网关访问
curl http://localhost:8080/api/orders/1001

# 熔断测试:停掉 user-service 后再次请求
# 应该返回 fallback 结果

预期输出

{
  "orderId": 1001,
  "product": "MacBook Pro",
  "user": {
    "id": 1,
    "name": "Alice",
    "email": "alice@example.com"
  }
}

教程

Spring Cloud 微服务架构设计指南

第一章:服务注册与发现

1.1 为什么需要注册中心?

在微服务架构中,服务实例动态变化(扩容、缩容、故障),需要一种机制让服务消费者自动发现可用的服务提供者。

[User Service 实例1] ──注册──→ [Eureka Server]
[User Service 实例2] ──注册──→      ↑
[Order Service]      ──发现─────────┘

1.2 Eureka 核心配置

# Eureka Server
eureka:
  server:
    enable-self-preservation: false  # 开发环境关闭自我保护
    eviction-interval-timer-in-ms: 5000

# Eureka Client
eureka:
  client:
    registry-fetch-interval-seconds: 30  # 拉取注册表间隔
  instance:
    lease-renewal-interval-in-seconds: 10  # 心跳间隔
    lease-expiration-duration-in-seconds: 30  # 过期时间
    prefer-ip-address: true  # 优先使用 IP 注册

第二章:API 网关设计

2.1 Gateway vs Zuul

特性 Spring Cloud Gateway Netflix Zuul
底层 WebFlux (Netty) Servlet (Tomcat)
性能 非阻塞、高并发 阻塞式,性能较低
维护状态 活跃 进入维护模式
推荐 ✅ 新项目首选 ❌ 遗留项目

2.2 Gateway 路由与过滤器

spring:
  cloud:
    gateway:
      routes:
        - id: custom-route
          uri: lb://target-service
          predicates:
            - Path=/api/v1/**
            - Header=X-API-Version, 2
            - Method=GET,POST
          filters:
            - AddRequestHeader=X-Gateway, true
            - name: CircuitBreaker
              args:
                name: fallbackCmd
                fallbackUri: forward:/fallback

2.3 全局过滤器

@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getHeaders()
            .getFirst("Authorization");
        if (token == null) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -1;  // 高优先级
    }
}

第三章:声明式 HTTP 调用

3.1 Feign 最佳实践

@FeignClient(name = "user-service", configuration = FeignConfig.class)
public interface UserClient {

    @GetMapping("/users/{id}")
    UserDto getUser(@PathVariable Long id);

    @PostMapping("/users")
    UserDto create(@RequestBody CreateUserRequest request);

    @GetMapping("/users")
    Page<UserDto> list(@SpringQueryMap UserQuery query);
}

// 统一配置
@Configuration
public class FeignConfig {
    @Bean
    public RequestInterceptor authInterceptor() {
        return requestTemplate -> {
            requestTemplate.header("Authorization",
                "Bearer " + getCurrentToken());
        };
    }

    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;  // 完整日志
    }
}

第四章:熔断与降级

4.1 Resilience4j 三种模式

// 1. 熔断器 (Circuit Breaker)
@CircuitBreaker(name = "userService", fallbackMethod = "fallback")
public UserDto getUser(Long id) { ... }
public UserDto fallback(Long id, Throwable t) {
    return new UserDto(id, "Default", "N/A");
}

// 2. 重试 (Retry)
@Retry(name = "userService", fallbackMethod = "fallback")
public UserDto getUserWithRetry(Long id) { ... }

// 3. 限流 (Rate Limiter)
@RateLimiter(name = "userService")
public UserDto getUserWithRateLimit(Long id) { ... }

// 4. 组合使用
@Bulkhead(name = "userService")  // 隔仓
@CircuitBreaker(name = "userService")
@Retry(name = "userService")
public UserDto getUserWithFullProtection(Long id) { ... }

4.2 配置示例

resilience4j:
  circuitbreaker:
    instances:
      userService:
        sliding-window-size: 10        # 滑动窗口大小
        minimum-number-of-calls: 5     # 最小调用次数
        failure-rate-threshold: 50     # 失败率阈值(%)
        wait-duration-in-open-state: 30s
        permitted-number-of-calls-in-half-open-state: 3
  retry:
    instances:
      userService:
        max-attempts: 3
        wait-duration: 500ms
        retry-exceptions:
          - java.net.ConnectException

第五章:配置中心

5.1 Config Server + Bus 动态刷新

# Config Server
spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/myorg/config-repo
          search-paths: '{application}'
// 客户端使用 @RefreshScope
@RestController
@RefreshScope  // 配置变化时自动刷新
public class ConfigController {
    @Value("${app.message}")
    private String message;

    @GetMapping("/message")
    public String getMessage() {
        return message;
    }
}
# 触发批量刷新
curl -X POST http://localhost:8080/actuator/busrefresh

思考题

  1. 服务注册中心 CAP 权衡:Eureka(AP)vs Consul(CP)vs Nacos(AP+CP)如何选择?
  2. Gateway 中如何实现基于请求体的路由?
  3. Feign 底层如何实现负载均衡?
  4. 分布式事务在微服务中有哪些解决方案?

参考资料

  1. [1] Spring Team. Spring Cloud Reference. 2024. https://docs.spring.io/spring-cloud/docs/current/reference/html/
  2. [2] John Carnell, Illary Huaylupo Sánchez. Spring Microservices in Action. 2021.
  3. [3] Chris Richardson. Microservices Patterns. 2018.
  4. [4] Sam Newman. Building Microservices (2nd Edition). 2021.