Skip to content

Spring Cloud 微服务架构框架

概述

Spring Cloud 是基于 Spring Boot 的一套微服务开发工具集,为开发者提供了快速构建分布式系统中一些常见模式的工具(如配置管理、服务发现、断路器、智能路由、微代理、控制总线等)。

Spring Cloud 专注于提供良好的开箱即用体验的典型用例和可扩展性机制覆盖其他用例。

什么是微服务?

微服务架构是一种将单一应用程序拆分为多个小型、独立服务的架构风格。每个服务:

  • 运行在自己的进程中
  • 通过轻量级通信机制(通常是 HTTP API)进行通信
  • 围绕业务功能构建
  • 可以独立部署
  • 由小团队维护

Spring Cloud 核心组件

1. 服务注册与发现

Eureka - Netflix 开源的服务注册中心

kotlin
@SpringBootApplication
@EnableEurekaServer  // 启用Eureka服务端
class EurekaServerApplication

fun main(args: Array<String>) {
    runApplication<EurekaServerApplication>(*args)
}
java
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}
yaml
# application.yml - Eureka Server配置
server:
  port: 8761

eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: false # 不注册自己
    fetch-registry: false # 不获取注册信息
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

服务注册示例

kotlin
@SpringBootApplication
@EnableEurekaClient  // 启用Eureka客户端
@RestController
class UserServiceApplication {

    @GetMapping("/users/{id}")
    fun getUser(@PathVariable id: Long): User {
        return userService.findById(id)
    }
}

fun main(args: Array<String>) {
    runApplication<UserServiceApplication>(*args)
}
java
@SpringBootApplication
@EnableEurekaClient
@RestController
public class UserServiceApplication {

    @GetMapping("/users/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.findById(id);
    }

    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}
yaml
# 用户服务配置
spring:
  application:
    name: user-service # 服务名称

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

2. 服务调用

OpenFeign - 声明式的 HTTP 客户端

kotlin
@SpringBootApplication
@EnableFeignClients  // 启用Feign客户端
class OrderServiceApplication

// 定义Feign客户端接口
@FeignClient(name = "user-service")  // 指向用户服务
interface UserClient {

    @GetMapping("/users/{id}")
    fun getUser(@PathVariable id: Long): User
}

@RestController
class OrderController(private val userClient: UserClient) {

    @PostMapping("/orders")
    fun createOrder(@RequestBody orderRequest: OrderRequest): Order {
        // 通过Feign调用用户服务
        val user = userClient.getUser(orderRequest.userId)

        // 创建订单逻辑
        return orderService.createOrder(orderRequest, user)
    }
}
java
@SpringBootApplication
@EnableFeignClients
public class OrderServiceApplication {

    // Feign客户端接口
    @FeignClient(name = "user-service")
    public interface UserClient {

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

    @RestController
    public class OrderController {

        @Autowired
        private UserClient userClient;

        @PostMapping("/orders")
        public Order createOrder(@RequestBody OrderRequest orderRequest) {
            User user = userClient.getUser(orderRequest.getUserId());
            return orderService.createOrder(orderRequest, user);
        }
    }
}

Feign 会自动根据服务名从注册中心获取服务实例,实现负载均衡调用。

3. 负载均衡

Spring Cloud LoadBalancer - 客户端负载均衡

kotlin
@Configuration
class LoadBalancerConfig {

    @Bean
    @LoadBalanced  // 启用负载均衡
    fun restTemplate(): RestTemplate {
        return RestTemplate()
    }
}

@Service
class OrderService(private val restTemplate: RestTemplate) {

    fun getUserInfo(userId: Long): User {
        // 直接使用服务名调用,LoadBalancer会自动选择实例
        return restTemplate.getForObject(
            "http://user-service/users/$userId",
            User::class.java
        )!!
    }
}

负载均衡策略

kotlin
@Configuration
class CustomLoadBalancerConfig {

    @Bean
    fun randomLoadBalancer(): ReactorLoadBalancer<ServiceInstance> {
        return RandomLoadBalancer(
            LoadBalancerClientFactory.getLazyProvider("user-service", ServiceInstanceListSupplier::class.java),
            "user-service"
        )
    }
}

4. 断路器模式

Resilience4j - 容错库

kotlin
@Service
class OrderService {

    @CircuitBreaker(name = "user-service", fallbackMethod = "fallbackGetUser")
    @TimeLimiter(name = "user-service")
    @Retry(name = "user-service")
    fun getUser(userId: Long): CompletableFuture<User> {
        return CompletableFuture.supplyAsync {
            userClient.getUser(userId)
        }
    }

    // 降级方法
    fun fallbackGetUser(userId: Long, exception: Exception): CompletableFuture<User> {
        return CompletableFuture.completedFuture(
            User(id = userId, name = "默认用户", email = "default@example.com")
        )
    }
}
yaml
# Resilience4j配置
resilience4j:
  circuitbreaker:
    instances:
      user-service:
        failure-rate-threshold: 50 # 失败率阈值50%
        wait-duration-in-open-state: 10000 # 断路器开启等待时间10秒
        sliding-window-size: 10 # 滑动窗口大小
        minimum-number-of-calls: 5 # 最小调用次数

  retry:
    instances:
      user-service:
        max-attempts: 3
        wait-duration: 1000

  timelimiter:
    instances:
      user-service:
        timeout-duration: 3000 # 超时时间3秒

5. API 网关

Spring Cloud Gateway - 基于 WebFlux 的网关

kotlin
@SpringBootApplication
class GatewayApplication

fun main(args: Array<String>) {
    runApplication<GatewayApplication>(*args)
}

@Configuration
class GatewayConfig {

    @Bean
    fun routeLocator(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            .route("user-service") { r ->
                r.path("/api/users/**")
                    .uri("lb://user-service")  // 负载均衡到用户服务
            }
            .route("order-service") { r ->
                r.path("/api/orders/**")
                    .uri("lb://order-service")
            }
            .build()
    }
}
java
@SpringBootApplication
public class GatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }

    @Configuration
    public class GatewayConfig {

        @Bean
        public RouteLocator routeLocator(RouteLocatorBuilder builder) {
            return builder.routes()
                .route("user-service", r ->
                    r.path("/api/users/**")
                     .uri("lb://user-service"))
                .route("order-service", r ->
                    r.path("/api/orders/**")
                     .uri("lb://order-service"))
                .build();
        }
    }
}

Gateway 过滤器示例

kotlin
@Component
class AuthGatewayFilterFactory : AbstractGatewayFilterFactory<AuthGatewayFilterFactory.Config>() {

    override fun apply(config: Config): GatewayFilter {
        return GatewayFilter { exchange, chain ->
            val request = exchange.request
            val token = request.headers.getFirst("Authorization")

            if (token.isNullOrBlank()) {
                val response = exchange.response
                response.statusCode = HttpStatus.UNAUTHORIZED
                return@GatewayFilter response.setComplete()
            }

            // 验证token逻辑
            if (!isValidToken(token)) {
                val response = exchange.response
                response.statusCode = HttpStatus.FORBIDDEN
                return@GatewayFilter response.setComplete()
            }

            chain.filter(exchange)
        }
    }

    private fun isValidToken(token: String): Boolean {
        // 实际的token验证逻辑
        return true
    }

    class Config {
        // 配置属性
    }
}

6. 配置中心

Spring Cloud Config - 分布式配置管理

kotlin
@SpringBootApplication
@EnableConfigServer  // 启用配置服务端
class ConfigServerApplication

fun main(args: Array<String>) {
    runApplication<ConfigServerApplication>(*args)
}
java
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}
yaml
# Config Server配置
server:
  port: 8888

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/your-org/config-repo # 配置仓库
          search-paths: configs # 搜索路径

客户端配置

yaml
# bootstrap.yml - 配置客户端
spring:
  application:
    name: user-service
  cloud:
    config:
      uri: http://localhost:8888 # 配置中心地址
      profile: dev # 环境配置
      label: master # 分支

动态配置刷新

kotlin
@RestController
@RefreshScope  // 支持配置动态刷新
class UserController {

    @Value("\${user.default.age:18}")
    private var defaultAge: Int = 18

    @GetMapping("/config")
    fun getConfig(): Map<String, Any> {
        return mapOf("defaultAge" to defaultAge)
    }
}

实际业务场景示例

电商系统微服务架构

让我们通过一个完整的电商系统来演示 Spring Cloud 的使用:

订单服务示例代码
kotlin
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
class OrderServiceApplication

fun main(args: Array<String>) {
    runApplication<OrderServiceApplication>(*args)
}

// 用户服务客户端
@FeignClient(name = "user-service")
interface UserClient {
    @GetMapping("/users/{id}")
    fun getUser(@PathVariable id: Long): User
}

// 商品服务客户端
@FeignClient(name = "product-service")
interface ProductClient {
    @GetMapping("/products/{id}")
    fun getProduct(@PathVariable id: Long): Product

    @PostMapping("/products/{id}/stock/reduce")
    fun reduceStock(@PathVariable id: Long, @RequestParam quantity: Int): Boolean
}

// 支付服务客户端
@FeignClient(name = "payment-service")
interface PaymentClient {
    @PostMapping("/payments")
    fun processPayment(@RequestBody paymentRequest: PaymentRequest): PaymentResult
}

@RestController
@RequestMapping("/orders")
class OrderController(
    private val orderService: OrderService
) {

    @PostMapping
    fun createOrder(@RequestBody orderRequest: OrderRequest): ResponseEntity<Order> {
        return try {
            val order = orderService.createOrder(orderRequest)
            ResponseEntity.ok(order)
        } catch (e: Exception) {
            ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build()
        }
    }

    @GetMapping("/{id}")
    fun getOrder(@PathVariable id: Long): ResponseEntity<Order> {
        val order = orderService.getOrder(id)
        return if (order != null) {
            ResponseEntity.ok(order)
        } else {
            ResponseEntity.notFound().build()
        }
    }
}

@Service
@Transactional
class OrderService(
    private val userClient: UserClient,
    private val productClient: ProductClient,
    private val paymentClient: PaymentClient,
    private val orderRepository: OrderRepository
) {

    @CircuitBreaker(name = "order-service", fallbackMethod = "fallbackCreateOrder")
    @Retry(name = "order-service")
    fun createOrder(orderRequest: OrderRequest): Order {

        // 1. 验证用户
        val user = userClient.getUser(orderRequest.userId)
            ?: throw IllegalArgumentException("用户不存在")

        // 2. 验证商品并减库存
        val products = mutableListOf<Product>()
        for (item in orderRequest.items) {
            val product = productClient.getProduct(item.productId)
                ?: throw IllegalArgumentException("商品不存在: ${item.productId}")

            val stockReduced = productClient.reduceStock(item.productId, item.quantity)
            if (!stockReduced) {
                throw IllegalStateException("库存不足: ${item.productId}")
            }

            products.add(product)
        }

        // 3. 创建订单
        val order = Order(
            userId = user.id,
            items = orderRequest.items,
            totalAmount = calculateTotalAmount(orderRequest.items, products),
            status = OrderStatus.CREATED
        )

        val savedOrder = orderRepository.save(order)

        // 4. 处理支付
        val paymentRequest = PaymentRequest(
            orderId = savedOrder.id,
            amount = savedOrder.totalAmount,
            paymentMethod = orderRequest.paymentMethod
        )

        val paymentResult = paymentClient.processPayment(paymentRequest)

        // 5. 更新订单状态
        savedOrder.status = if (paymentResult.success) {
            OrderStatus.PAID
        } else {
            OrderStatus.PAYMENT_FAILED
        }

        return orderRepository.save(savedOrder)
    }

    // 降级方法
    fun fallbackCreateOrder(orderRequest: OrderRequest, ex: Exception): Order {
        return Order(
            userId = orderRequest.userId,
            items = orderRequest.items,
            totalAmount = BigDecimal.ZERO,
            status = OrderStatus.FAILED,
            errorMessage = "服务暂时不可用,请稍后重试"
        )
    }

    private fun calculateTotalAmount(items: List<OrderItem>, products: List<Product>): BigDecimal {
        return items.sumOf { item ->
            val product = products.find { it.id == item.productId }!!
            product.price.multiply(BigDecimal(item.quantity))
        }
    }
}

监控与追踪

Spring Boot Actuator + Micrometer

kotlin
// 添加监控端点
@Component
class CustomHealthIndicator : HealthIndicator {

    override fun health(): Health {
        val isHealthy = checkDatabaseConnection()

        return if (isHealthy) {
            Health.up()
                .withDetail("database", "可用")
                .withDetail("diskSpace", "充足")
                .build()
        } else {
            Health.down()
                .withDetail("database", "不可用")
                .build()
        }
    }

    private fun checkDatabaseConnection(): Boolean {
        // 实际的健康检查逻辑
        return true
    }
}

// 自定义指标
@Component
class OrderMetrics(meterRegistry: MeterRegistry) {

    private val orderCounter = Counter.builder("orders.created")
        .description("创建的订单数量")
        .register(meterRegistry)

    fun incrementOrderCount() {
        orderCounter.increment()
    }
}

分布式追踪

yaml
# 添加Sleuth依赖进行链路追踪
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,httptrace
  endpoint:
    health:
      show-details: always

# Zipkin配置
spring:
  sleuth:
    zipkin:
      base-url: http://localhost:9411
    sampler:
      probability: 1.0 # 采样率100%

最佳实践

1. 服务拆分原则

单一职责原则:每个服务应该有明确的业务边界和职责。

  • 按业务功能拆分:用户管理、订单处理、支付结算
  • 按数据边界拆分:避免跨服务的数据库事务
  • 按团队边界拆分:确保团队能够独立维护服务

2. 服务通信

kotlin
// 优先使用异步通信
@EventListener
class OrderEventHandler {

    @Async
    fun handleOrderCreated(orderCreatedEvent: OrderCreatedEvent) {
        // 发送邮件通知
        emailService.sendOrderConfirmation(orderCreatedEvent.orderId)

        // 更新库存
        inventoryService.updateInventory(orderCreatedEvent.items)
    }
}

// 使用消息队列进行解耦
@RabbitListener(queues = ["order.created"])
fun processOrderCreated(@Payload orderEvent: OrderCreatedEvent) {
    log.info("处理订单创建事件: ${orderEvent.orderId}")
    // 处理逻辑
}

3. 配置管理

将配置外部化,使用配置中心统一管理环境相关的配置。

yaml
# 按环境分离配置
# application-dev.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/ecommerce_dev

# application-prod.yml
spring:
  datasource:
    url: jdbc:mysql://prod-db:3306/ecommerce_prod

4. 错误处理和容错

kotlin
@ControllerAdvice
class GlobalExceptionHandler {

    @ExceptionHandler(FeignException::class)
    fun handleFeignException(ex: FeignException): ResponseEntity<ErrorResponse> {
        return ResponseEntity.status(ex.status())
            .body(ErrorResponse(
                code = "SERVICE_UNAVAILABLE",
                message = "服务暂时不可用",
                timestamp = Instant.now()
            ))
    }

    @ExceptionHandler(CircuitBreakerOpenException::class)
    fun handleCircuitBreakerOpen(ex: CircuitBreakerOpenException): ResponseEntity<ErrorResponse> {
        return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE)
            .body(ErrorResponse(
                code = "CIRCUIT_BREAKER_OPEN",
                message = "服务熔断中,请稍后重试"
            ))
    }
}

5. 安全考虑

kotlin
// JWT Token验证
@Component
class JwtAuthenticationFilter : OncePerRequestFilter() {

    override fun doFilterInternal(
        request: HttpServletRequest,
        response: HttpServletResponse,
        filterChain: FilterChain
    ) {
        val token = extractToken(request)

        if (token != null && jwtTokenProvider.validateToken(token)) {
            val authentication = jwtTokenProvider.getAuthentication(token)
            SecurityContextHolder.getContext().authentication = authentication
        }

        filterChain.doFilter(request, response)
    }
}

部署策略

Docker 容器化

dockerfile
# Dockerfile示例
FROM openjdk:11-jre-slim

VOLUME /tmp
COPY target/order-service-1.0.0.jar app.jar

EXPOSE 8083

ENTRYPOINT ["java", "-jar", "/app.jar"]

Docker Compose 部署

yaml
version: "3.8"
services:
  eureka-server:
    image: ecommerce/eureka-server:latest
    ports:
      - "8761:8761"

  config-server:
    image: ecommerce/config-server:latest
    ports:
      - "8888:8888"
    depends_on:
      - eureka-server

  user-service:
    image: ecommerce/user-service:latest
    ports:
      - "8081:8081"
    depends_on:
      - eureka-server
      - config-server
      - mysql
    environment:
      - SPRING_PROFILES_ACTIVE=docker

  order-service:
    image: ecommerce/order-service:latest
    ports:
      - "8083:8083"
    depends_on:
      - eureka-server
      - config-server
      - user-service
      - product-service

总结

Spring Cloud 为构建分布式系统提供了全面的解决方案:

TIP

核心优势

  • 开箱即用:提供了微服务开发所需的大部分组件
  • 生态完整:与 Spring Boot 无缝集成,社区活跃
  • 可扩展性:支持多种服务注册中心和配置中心
  • 容错能力:内置断路器、重试、超时等容错机制

微服务架构增加了系统复杂性,需要考虑服务间通信、数据一致性、分布式事务等问题。

通过合理使用 Spring Cloud 的各个组件,我们可以构建出健壮、可扩展的微服务系统,但同时也要注意避免过度设计,根据实际业务需求选择合适的架构模式。