Featured image of post Spring Cloud 实战:微服务、网关、安全一体化

Spring Cloud 实战:微服务、网关、安全一体化

Spring Cloud Finchley + Gateway + Security + Nacos + Sentinel 全套生产级方案

Spring Cloud 实战:微服务、网关、安全一体化

背景与价值

Spring Cloud 是 Java 生态事实标准微服务框架(Dubbo 主要在阿里系内部使用)。基于 Spring Boot,提供了配置中心、注册中心、网关、熔断、负载均衡、链路追踪等开箱即用的微服务组件。

2018 年 Spring Cloud Finchley 发布(基于 Spring Boot 2.0),标志着 Spring Cloud 进入"模块化、可插拔"阶段。本文按"版本演进 → 核心组件 → 选型 → 实战"完整路径展开。

版本演进时间线

发布年月Spring BootSpring CloudSpring Cloud Alibaba
2014-061.0--
2016-01-Angel.SR5-
2017-021.5--
2017-09--Alibaba 1.5.1
2018-032.0-Alibaba 2.0.4
2018-09-FinchleyAlibaba 2.1
2019-102.2Hoxton-
2020-052.3-Alibaba 2.2
2021-052.5--
2021-112.62021.0.x JubileeAlibaba 2021.0.x
2022-113.0(JDK 17+)2022.0.x KilburnAlibaba 2022.0.x
2023-113.2--

生产推荐组合(2024 稳定):

  • JDK 8:Spring Boot 2.6.14 + Spring Cloud 2021.0.7 + Alibaba 2021.0.5
  • JDK 17/21:Spring Boot 3.2+ + Spring Cloud 2023.0.x + Alibaba 2022.0.x

核心组件全景

类别Spring Cloud 官方Spring Cloud AlibabaSpring Cloud Netflix(已停更)
配置中心Spring Cloud ConfigNacos-
注册中心ConsulNacosEureka
服务熔断Resilience4jSentinelHystrix
服务调用OpenFeignDubbo RPCFeign
负载均衡Spring Cloud LoadBalancerDubbo LBRibbon
网关路由Spring Cloud Gateway-Zuul
消息总线Spring Cloud Bus--
链路追踪Sleuth + Zipkin--
分布式消息Spring Cloud StreamRocketMQ-
分布式事务-Seata-

2024 年 Netflix 套件(Hystrix / Ribbon / Zuul)已全部进入维护模式,新项目禁用

Spring Cloud Gateway 实战

1. 引入依赖

1
2
3
4
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

注意:Gateway 基于 WebFlux(响应式),不能引入 spring-boot-starter-web

2. 路由配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# application.yml
spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service           # lb:// = LoadBalancer 服务发现
          predicates:
            - Path=/api/user/**            # 路径匹配
          filters:
            - StripPrefix=2                # 去掉 /api/user 前缀
            - AddRequestHeader=X-Request-Id, ${UUID}
            - CircuitBreaker=myCircuitBreaker

        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/order/**
            - Method=POST,PUT
          filters:
            - StripPrefix=2
            - Retry=3                       # 重试 3 次

3. 全局过滤器(鉴权 + 日志)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Component
public class GlobalAuthFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String token = request.getHeaders().getFirst("Authorization");

        // 1. 白名单(无需 token)
        String path = request.getPath().value();
        if (path.startsWith("/api/auth/") || path.startsWith("/api/public/")) {
            return chain.filter(exchange);
        }

        // 2. 校验 token
        if (token == null || !validateToken(token)) {
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }

        // 3. 传递用户信息给下游服务
        ServerHttpRequest mutated = request.mutate()
            .header("X-User-Id", extractUserId(token))
            .build();
        return chain.filter(exchange.mutate().request(mutated).build());
    }

    @Override
    public int getOrder() {
        return -100;  // 数字越小越早执行
    }
}

4. CORS 跨域配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
@Configuration
public class CorsConfig {

    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOriginPattern("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        config.setAllowCredentials(true);
        config.setMaxAge(3600L);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return new CorsWebFilter(source);
    }
}

Nacos 注册中心 + 配置中心

Nacos 集成注册中心 + 配置中心,一站式替代 Eureka + Config + Bus

1. 服务注册

1
2
3
4
5
6
7
8
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
spring:
  application:
    name: user-service
  cloud:
    nacos:
      discovery:
        server-addr: {{NACOS_HOST}}:8848
        namespace: prod
        username: {{NACOS_USER}}
        password: {{NACOS_PASSWORD}}
      config:
        server-addr: {{NACOS_HOST}}:8848
        file-extension: yaml
        refresh-enabled: true
        shared-configs:
          - data-id: common.yaml
            refresh: true

2. 配置动态刷新

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@RestController
@RefreshScope   // 关键注解:nacos 配置变更时自动刷新 @Value
public class OrderController {

    @Value("${order.timeout:30}")
    private int timeout;

    @GetMapping("/timeout")
    public String getTimeout() {
        return "当前超时时间: " + timeout + " 秒";
    }
}

3. 集群部署(3 节点)

1
2
3
4
5
6
7
# 节点 1
sh startup.sh -m standalone          # 单机模式(仅测试)
sh startup.sh -m cluster             # 集群模式(生产)

# application.properties
nacos.cluster.name=Cluster-A
nacos.member.list=192.168.1.1:8848,192.168.1.2:8848,192.168.1.3:8848

集群模式需要 MySQL 存储(替代默认 Derby),3 节点 Raft 选举实现高可用。

Spring Security 实战

1. 引入依赖

1
2
3
4
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

2. 基础配置(用户名密码登录)

1
2
3
4
5
6
spring:
  security:
    user:
      name: admin
      password: {{ADMIN_PASSWORD}}   # 实际值从 Nacos 配置中心读取
      roles: ADMIN

默认会拦截所有请求,访问 http://localhost:8080 弹出登录框。

3. JWT 鉴权配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable())
            .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/auth/**", "/api/public/**").permitAll()
                .anyRequest().authenticated()
            )
            .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Component
public class JwtAuthFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        String token = request.getHeader("Authorization");
        if (token != null && token.startsWith("Bearer ")) {
            String jwt = token.substring(7);
            try {
                Claims claims = Jwts.parser()
                    .verifyWith(Keys.hmacShaKeyFor(secret.getBytes()))
                    .build()
                    .parseSignedClaims(jwt)
                    .getPayload();

                String username = claims.getSubject();
                List<String> roles = claims.get("roles", List.class);

                List<SimpleGrantedAuthority> authorities = roles.stream()
                    .map(r -> new SimpleGrantedAuthority("ROLE_" + r))
                    .collect(Collectors.toList());

                UsernamePasswordAuthenticationToken auth =
                    new UsernamePasswordAuthenticationToken(username, null, authorities);
                SecurityContextHolder.getContext().setAuthentication(auth);
            } catch (Exception e) {
                // token 无效
            }
        }
        chain.doFilter(request, response);
    }
}

OpenFeign 服务调用

1. 引入依赖

1
2
3
4
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2. 声明式调用

1
2
3
4
5
6
7
8
9
@FeignClient(name = "order-service", fallback = OrderClientFallback.class)
public interface OrderClient {

    @GetMapping("/api/order/{userId}")
    Result<List<Order>> listByUser(@PathVariable Long userId);

    @PostMapping("/api/order")
    Result<Order> create(@RequestBody OrderDTO order);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
@RestController
public class UserController {

    @Autowired
    private OrderClient orderClient;

    @GetMapping("/user/{id}/orders")
    public Result<List<Order>> getUserOrders(@PathVariable Long id) {
        return orderClient.listByUser(id);
    }
}

3. Fallback 降级

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@Component
public class OrderClientFallback implements OrderClient {

    @Override
    public Result<List<Order>> listByUser(Long userId) {
        return Result.fail("订单服务不可用,请稍后重试");
    }

    @Override
    public Result<Order> create(OrderDTO order) {
        return Result.fail("订单创建失败");
    }
}

Sentinel 熔断限流

1. 引入依赖

1
2
3
4
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

2. 控制台部署

1
2
3
4
5
docker run -d \
  -p 8858:8858 \
  -p 8719:8719 \
  --name sentinel-dashboard \
  bladex/sentinel-dashboard:1.8.6

访问 http://localhost:8858,账号 sentinel / sentinel

3. 流量控制规则(代码方式)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@PostConstruct
public void initFlowRules() {
    List<FlowRule> rules = new ArrayList<>();
    FlowRule rule = new FlowRule("userService");
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    rule.setCount(100);                // QPS 阈值
    rule.setLimitApp("default");
    rules.add(rule);
    FlowRuleManager.loadRules(rules);
}

链路追踪(Sleuth + Zipkin)

1
2
3
4
5
6
7
8
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.zipkin</groupId>
    <artifactId>zipkin-reporter-brave</artifactId>
</dependency>
1
2
3
4
5
6
spring:
  zipkin:
    base-url: http://{{ZIPKIN_HOST}}:9411
  sleuth:
    sampler:
      probability: 0.1    # 采样率 10%

每次 HTTP 请求会自动注入 X-B3-TraceId / X-B3-SpanId,通过 Zipkin UI 看到完整调用链。

微服务方案选型决策

场景推荐方案
传统企业(Java 8 为主)Spring Cloud 2021.0.x + Alibaba 2021.0.x
新项目(Java 17/21)Spring Cloud 2023.0.x + Alibaba 2022.0.x
高吞吐业务Spring Cloud Gateway + Sentinel + RocketMQ
阿里系Spring Cloud Alibaba(Nacos + Sentinel + Seata)
多语言异构Spring Cloud Gateway + gRPC + Nacos

前置知识与下一步

前置

  • Spring Boot 基础
  • 微服务基本概念(服务注册 / 发现 / 熔断)
  • Linux + Docker 基础

下一步

  • 分布式事务:Spring Cloud Alibaba Seata(AT/TCC/SAGA/XA 4 种模式)
  • 配置中心深度:Nacos 长轮询 + 灰度发布
  • 监控:Spring Boot Admin + Actuator + Prometheus + Grafana

小结

Spring Cloud 2021.0.x(Jubilee) + Spring Cloud Alibaba 2021.0.x 是当前最稳定的 Java 微服务组合。Nacos 一体化注册 + 配置中心Sentinel 替代 HystrixSeata 解决分布式事务Gateway 替代 Zuul,是核心 4 件套。新项目直接基于 Spring Boot 3.2+ + Spring Cloud 2023.0.x,老项目维持 Spring Boot 2.6 + Spring Cloud 2021.0.x。


2024+ 视角:Spring Cloud 2024 / 2025 与 Spring AI

Spring Cloud 版本节奏(2024 视角)

发布年份Spring BootSpring CloudSpring Cloud Alibaba关键变化
2024-113.42024.0.x2023.0.xJDK 17+ 强制
2025-053.52025.0.x2023.0.xSpring AI 1.0 GA

生产推荐

  • JDK 17:Spring Boot 3.4 + Spring Cloud 2024.0.x + Alibaba 2023.0.x
  • JDK 21:Spring Boot 3.5 + Spring Cloud 2025.0.x + Alibaba 2023.0.x

Spring AI 1.0(2025 GA)

Spring 官方推出的 LLM 集成框架——类似 LangChain 的 Java 版:

1
2
3
4
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
@RestController
public class ChatController {

    private final ChatClient chatClient;

    public ChatController(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    @GetMapping("/chat")
    public String chat(@RequestParam String message) {
        return chatClient.prompt()
            .user(message)
            .call()
            .content();
    }
}

核心能力

  • 多模型支持(OpenAI / Anthropic / Azure / Ollama / DeepSeek / 通义千问)
  • Function Calling(让 LLM 调 Java 方法)
  • RAG(向量库集成:pgvector / Milvus / Qdrant)
  • Prompt Template + 结构化输出

Spring Cloud Gateway 4.x 新特性

  • 响应式 API 更完善ServerWebExchange + Reactor 性能 +30%
  • GraphQL 路由:内置 GraphQL endpoint
  • WebSocket 增强:原生支持 WebSocket 路由
  • gRPC 集成:spring-cloud-starter-gateway + grpc-gateway 双向

Spring Cloud Stream 4.x + Kafka 3.x

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
spring:
  cloud:
    stream:
      bindings:
        output:
          destination: orders
          content-type: application/json
      kafka:
        binder:
          brokers: kafka:9092
          configuration:
            compression.type: zstd       # 2024+ 默认压缩
            linger.ms: 20

2024+ 选型:Spring Cloud vs Istio

场景Spring CloudIstio / 服务网格
传统 Java 微服务✅ 首选
多语言(Go / Python / Node)一般✅ 首选
流量管理复杂一般✅ 蓝绿/金丝雀/镜像
学习成本
性能开销中(Sidecar 5-10%)

2024+ 趋势Spring Cloud + Istio 双层——Java 业务用 Spring Cloud 简化,跨语言/灰度发布用 Istio 解决。

国产化适配

  • Spring Cloud Alibaba 2023.0.x 适配 Spring Boot 3.4+
  • Nacos 2.3+ 支持国密算法(SM2/SM3/SM4)
  • Sentinel 1.8.8+ 流量规则支持 Prometheus metrics 导出
  • Seata 2.x TC Server 高可用增强(Raft 共识)

2024+ 实战坑

  • JDK 17 / 21 反射限制--add-opens java.base/java.lang=ALL-UNNAMED 等参数要加到启动脚本
  • Spring Boot 3.x Jakarta EE 9+javax.*jakarta.* 全量替换
  • Spring Cloud 2024.0.x 强制 Netty 4.1.x——有自定义 Netty handler 的项目要注意 API 变更
  • Spring AI 还在快速迭代——生产用建议锁定 1.0 GA 版本,别追 1.1-SNAPSHOT

2024+ 推荐组合

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
Java 后端服务(ToB、传统企业)
├── JDK 17 / 21
├── Spring Boot 3.4 / 3.5
├── Spring Cloud 2024.0.x / 2025.0.x
├── Spring Cloud Alibaba 2023.0.x
│   ├── Nacos 2.3+ (注册 + 配置)
│   ├── Sentinel 1.8.8+ (熔断限流)
│   ├── Seata 2.x (分布式事务)
│   └── RocketMQ 5.x (消息)
├── Spring Cloud Gateway 4.x (网关)
├── OpenFeign 4.x (RPC)
├── Resilience4j 2.x (熔断,替代 Hystrix)
├── Micrometer + Prometheus + Grafana (监控)
├── OpenTelemetry (Tracing)
└── Spring AI 1.0 (AI 能力,可选)
使用 Hugo 构建
主题 StackJimmy 设计