前置知识: Java

Java与微服务

8 minAdvanced2026/6/14

Spring Cloud微服务架构

概述

微服务是一种架构风格,将一个大型应用拆分为多个小型、独立的服务,每个服务负责一个业务领域,独立开发、独立部署、独立运行。服务之间通过 HTTP 或消息队列通信。与单体应用相比,微服务的优势在于:可以独立部署和扩展、技术栈可以不同、故障隔离更好。

Spring Cloud 是 Java 生态中最成熟的微服务框架,它基于 Spring Boot,提供了一整套微服务基础设施:服务注册与发现、配置管理、负载均衡、熔断降级、API 网关等。Spring Cloud 的组件经历了从 Netflix OSS 到 Spring Cloud Alibaba 的演进,国内项目普遍采用 Spring Cloud Alibaba 方案。

基础概念

微服务核心组件

一个完整的微服务架构需要以下基础组件:

  • 服务注册与发现:服务启动时将自己的地址注册到注册中心,其他服务通过注册中心发现对方。Nacos 是目前国内最流行的选择
  • 配置中心:集中管理所有服务的配置,支持动态刷新。Nacos 同时提供配置中心功能
  • 负载均衡:当某个服务有多个实例时,请求需要分发到不同实例。Spring Cloud LoadBalancer 是默认实现
  • API 网关:所有外部请求通过网关进入,网关负责路由、鉴权、限流等。Spring Cloud Gateway 是官方推荐
  • 熔断降级:当某个服务不可用时,快速失败而不是等待超时,防止故障蔓延。Sentinel 是国内主流选择
  • 声明式 HTTP 客户端:简化服务间的 HTTP 调用。OpenFeign 是标准方案

微服务与单体架构的选择

微服务不是银弹。团队规模小、业务复杂度低时,单体应用更简单高效。只有当团队超过一定规模、业务模块边界清晰、部署频率高到单体难以承受时,才考虑微服务。

快速上手

添加 Spring Cloud 依赖

Spring Cloud 基于 Spring Boot,版本需要匹配。在父 pom.xml 中添加:

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>3.2.0</version>
</parent>

<dependencyManagement>
  <dependencies>
    <!-- Spring Cloud 依赖管理 -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>2023.0.0</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
    <!-- Spring Cloud Alibaba 依赖管理 -->
    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-alibaba-dependencies</artifactId>
      <version>2023.0.0.0</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

服务注册到 Nacos

在服务提供方添加 Nacos 发现依赖:

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

配置 Nacos 地址:

# application.yml
spring:
  application:
    name: user-service # 服务名称
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # Nacos 服务器地址

启动上添加服务发现注解:

import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@EnableDiscoveryClient  // 启用服务发现
@SpringBootApplication
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

启动后,user-service 会自动注册到 Nacos,其他服务可以通过服务名找到它。

详细用法

1. 使用 OpenFeign 调用远程服务

OpenFeign 让你像调用本地方法一样调用远程服务:

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

// 定义 Feign 客户端接口
// name 指定要调用的服务名(在 Nacos 中注册的名称)
@FeignClient(name = "order-service")
public interface OrderClient {

    // 调用 order-service 的 /orders/user/{userId} 接口
    @GetMapping("/orders/user/{userId}")
    List<Order> getOrdersByUserId(@PathVariable("userId") Long userId);
}

启用 Feign 客户端:

import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@EnableFeignClients  // 启用 Feign 客户端扫描
@SpringBootApplication
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

在业务代码中使用:

import org.springframework.stereotype.Service;

@Service
public class UserBusinessService {

    private final OrderClient orderClient;

    public UserBusinessService(OrderClient orderClient) {
        this.orderClient = orderClient;
    }

    public UserDetail getUserDetail(Long userId) {
        // 像调用本地方法一样调用远程服务
        List<Order> orders = orderClient.getOrdersByUserId(userId);
        // 组装用户详情...
        return new UserDetail(userId, orders);
    }
}

2. Spring Cloud Gateway API 网关

网关是微服务的统一入口,处理路由、鉴权、限流等横切关注点:

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

配置路由规则:

# application.yml
server:
  port: 8080

spring:
  cloud:
    gateway:
      routes:
        # 用户服务路由
        - id: user-service
          uri: lb://user-service # lb:// 表示从注册中心获取实例并负载均衡
          predicates:
            - Path=/api/users/** # 匹配路径
          filters:
            - StripPrefix=1 # 去掉路径的第一段(/api)

        # 订单服务路由
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**
          filters:
            - StripPrefix=1

自定义全局过滤器(如鉴权):

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

@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 || !validateToken(token)) {
            // 令牌无效,返回 401
            exchange.getResponse().setStatusCode(org.springframework.http.HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        // 令牌有效,继续执行
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -1;  // 优先级,数字越小越先执行
    }

    private boolean validateToken(String token) {
        // 实际的令牌验证逻辑
        return token.startsWith("Bearer ");
    }
}

3. Sentinel 熔断降级

当某个服务不可用时,熔断器会快速失败,避免请求堆积导致整个系统崩溃:

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

配置 Sentinel:

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080 # Sentinel 控制台地址

使用 @SentinelResource 注解保护方法:

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    // 使用 Sentinel 保护此方法
    @SentinelResource(value = "getOrder",
        blockHandler = "getOrderBlockHandler",    // 限流时的处理方法
        fallback = "getOrderFallback")             // 异常时的降级方法
    public Order getOrder(Long orderId) {
        // 调用远程服务或数据库
        return orderRepository.findById(orderId).orElse(null);
    }

    // 限流时的处理(方法签名需要与原方法一致,加一个 BlockException 参数)
    public Order getOrderBlockHandler(Long orderId, BlockException ex) {
        System.out.println("请求被限流: " + orderId);
        return new Order(orderId, "服务繁忙,请稍后重试");
    }

    // 异常时的降级处理
    public Order getOrderFallback(Long orderId, Throwable throwable) {
        System.out.println("服务降级: " + throwable.getMessage());
        return new Order(orderId, "服务暂时不可用");
    }
}

4. Nacos 配置中心

Nacos 不仅可以做服务注册,还可以做配置中心,集中管理所有服务的配置:

<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
# bootstrap.yml(配置中心需要在应用上下文初始化之前加载)
spring:
  application:
    name: user-service
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
        file-extension: yaml # 配置文件格式

在 Nacos 控制台创建配置,Data ID 为 user-service.yaml,内容为:

# Nacos 上的配置
database:
  url: jdbc:mysql://prod-server:3306/user_db
  username: prod_user
  password: prod_password

应用启动时会自动从 Nacos 拉取配置。修改 Nacos 上的配置后,应用可以动态刷新:

import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.beans.factory.annotation.Value;

@RestController
@RefreshScope  // 支持配置动态刷新
public class ConfigController {

    @Value("${database.url}")
    private String dbUrl;

    @GetMapping("/config/db-url")
    public String getDbUrl() {
        return dbUrl;  // Nacos 配置变更后,这个值会自动更新
    }
}

5. 分布式链路追踪

微服务中一个请求可能经过多个服务,需要链路追踪来排查问题:

<dependency>
  <groupId>io.micrometer</groupId>
  <artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
<dependency>
  <groupId>io.zipkin.reporter2</groupId>
  <artifactId>zipkin-reporter-brave</artifactId>
</dependency>
management:
  tracing:
    sampling:
      probability: 1.0 # 采样率(1.0 表示全部采样,生产环境可以降低)
  zipkin:
    tracing:
      endpoint: http://localhost:9411/api/v2/spans # Zipkin 服务器地址

配置后,每个请求会自动生成 traceId,通过 Zipkin UI 可以查看请求在各个服务间的调用链路和耗时。

常见场景

场景一:服务间认证

微服务之间的调用也需要认证,常见做法是在网关验证令牌后,将用户信息通过请求头传递给下游服务:

// 网关过滤器:验证令牌后添加用户信息头
@Component
public class AuthFilter implements GlobalFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        String userId = validateToken(token);  // 验证令牌并提取用户ID

        // 将用户信息添加到请求头,传递给下游服务
        ServerHttpRequest request = exchange.getRequest().mutate()
            .header("X-User-Id", userId)
            .build();

        return chain.filter(exchange.mutate().request(request).build());
    }
}

场景二:灰度发布

通过网关的权重路由实现灰度发布,将部分流量导向新版本:

spring:
  cloud:
    gateway:
      routes:
        - id: user-service-v1
          uri: lb://user-service-v1
          predicates:
            - Path=/api/users/**
            - Weight=group1, 90 # 90% 的流量
        - id: user-service-v2
          uri: lb://user-service-v2
          predicates:
            - Path=/api/users/**
            - Weight=group1, 10 # 10% 的流量

注意事项与常见错误

不要过度拆分服务

服务拆得过细会导致服务间调用链过长,增加延迟和复杂度。一个好的服务应该有明确的业务边界,通常对应一个业务领域或一个团队。

分布式事务问题

微服务中,一个业务操作可能涉及多个服务的数据修改,无法使用本地事务保证一致性。解决方案包括:Saga 模式(编排或协调)、Seata 框架、最终一致性(通过消息队列)。不要强求强一致性,大多数业务场景用最终一致性就够了。

服务间循环依赖

服务 A 调用服务 B,服务 B 又调用服务 A,形成循环依赖。这通常说明服务边界划分有问题,需要重新梳理业务领域,将公共逻辑抽取为独立服务。

配置优先级

Spring Cloud 中配置的优先级从高到低为:命令行参数 > Nacos 配置 > application.yml > 默认值。理解这个优先级对排查配置问题很重要。

进阶用法

服务网格

服务网格(Service Mesh)是微服务架构的下一步演进,将服务间通信、安全、可观测性等能力从应用代码中剥离到基础设施层。Istio 是最流行的服务网格实现。Spring Cloud 与服务网格可以共存,Spring Cloud 处理业务逻辑,服务网格处理通信基础设施。

DDD 驱动的微服务设计

领域驱动设计(DDD)是微服务拆分的最佳方法论。通过识别限界上下文(Bounded Context),每个微服务对应一个限界上下文,服务内部保持高内聚,服务之间通过领域事件通信。

Kubernetes 部署

Spring Cloud 微服务通常部署在 Kubernetes 上,利用 K8s 的服务发现、自动扩缩容、滚动更新等能力。Spring Cloud Kubernetes 提供了与 K8s 集成的支持,可以直接使用 K8s 的 Service 发现机制替代 Nacos。