【SpringCloud】网关GateWay && Spring Cloud Gateway && Route Predicate Factories

文章目录

  • [Ⅰ. 网关介绍](#Ⅰ. 网关介绍)
    • 一、问题
    • 二、什么是API网关
    • 三、常见网关实现
      • [1️⃣ Spring Cloud Gateway(主流首选)](#1️⃣ Spring Cloud Gateway(主流首选))
      • [2️⃣ Zuul(Zuul 1 / Zuul 2)](#2️⃣ Zuul(Zuul 1 / Zuul 2))
      • [3️⃣ Nginx / OpenResty](#3️⃣ Nginx / OpenResty)
      • [4️⃣ Envoy](#4️⃣ Envoy)
      • [5️⃣ Kong](#5️⃣ Kong)
      • [6️⃣ Traefik](#6️⃣ Traefik)
      • [7️⃣ 云厂商网关](#7️⃣ 云厂商网关)
  • [Ⅱ. Spring Cloud Gateway](#Ⅱ. Spring Cloud Gateway)
    • 一、快速上手
      • [① 创建网关项目](#① 创建网关项目)
      • [② 引入网关依赖](#② 引入网关依赖)
      • [③ 编写启动类](#③ 编写启动类)
      • [④ 添加Gateway的路由配置](#④ 添加Gateway的路由配置)
      • [⑤ 测试](#⑤ 测试)
    • [二、Route Predicate Factories(路由断言工厂)](#二、Route Predicate Factories(路由断言工厂))
      • [① Predicate](#① Predicate)
      • [② Route Predicate Factories](#② Route Predicate Factories)

Ⅰ. 网关介绍

一、问题

前面学习中通过 EurekaNacos 解决了服务注册、服务发现的问题,使用 Spring Cloud LoadBalance 解决了负载均衡的问题,使用 OpenFeign 解决了远程调用的问题。

但是当前所有微服务的接口都是直接对外暴露的,可以直接通过外部访问。为了保证对外服务的安全性,服务端实现的微服务接口通常都带有一定的权限校验机制。并且由于使用了微服务,原本一个应用的的多个模块拆分成了多个应用,我们不得不实现多次校验逻辑。当这套逻辑需要修改时,需要同时修改多个应用,这加重了开发人员的负担。

为了解决以上问题,可以使用 API 网关。

二、什么是API网关

API网关(简称网关)也是一个服务,通常是后端服务的唯一入口。它的定义类似设计模式中的 Facade 模式(门面模式,也称外观模式)。

它就类似整个微服务架构的门面,所有的外部客户端访问,都需要经过它来进行调度和过滤。

但它比门面模式的功能要丰富很多,经典门面模式只是接口封装 ,不关心网络、路由、安全、限流;而 API 网关是一个企业级流量治理层,还承担了鉴权、路由、限流等基础设施能力。

维度 代码级 Facade Spring Cloud Gateway
层级 应用内 系统边界
关注点 业务流程 流量 & 安全
调用方式 方法调用 HTTP / WebFlux
是否有业务逻辑 几乎没有
是否是门面思想 ✔(强化版)

网关核心功能:

  • 统一入口(门面)
  • 屏蔽内部服务拓扑
  • 依赖收敛
  • 路由
  • 鉴权
  • 限流
  • 熔断
  • 监控
  • 协议转换

三、常见网关实现

1️⃣ Spring Cloud Gateway(主流首选)

定位:官方微服务网关

技术栈:WebFlux + Reactor(非阻塞)

核心能力

  • 动态路由(基于服务发现)
  • 全局 / 局部 Filter
  • 鉴权、限流、熔断
  • 与 Spring Cloud 生态深度集成

适用场景

  • Spring Cloud 微服务
  • 需要统一鉴权、限流、监控

评价

企业级标配,99% Java 微服务项目首选

2️⃣ Zuul(Zuul 1 / Zuul 2)

定位:早期 Netflix 网关

  • Zuul 1:阻塞式(Servlet)
  • Zuul 2:异步(但生态断层)

现状

  • 已被 Spring Cloud Gateway 取代
  • 新项目不推荐

面试话术

Zuul 是历史方案,Gateway 是演进方案

3️⃣ Nginx / OpenResty

定位:反向代理 / 七层网关

核心能力

  • 反向代理、负载均衡
  • SSL 终止
  • 限流、黑白名单
  • OpenResty 可写 Lua 扩展逻辑

适用场景

  • 网关最前置一层
  • 高并发、低延迟
  • 简单路由 + 防护

典型架构

Plain 复制代码
Client
  ↓
Nginx
  ↓
Spring Cloud Gateway

4️⃣ Envoy

定位:云原生 / Service Mesh 网关

核心能力

  • 高性能 L7 Proxy
  • gRPC / HTTP2
  • 动态配置(xDS)
  • 可观测性极强

适用场景

  • Kubernetes
  • Istio / Service Mesh
  • 大规模微服务

评价

技术先进,但学习成本高

5️⃣ Kong

定位:基于 Nginx 的 API Gateway

核心能力

  • 插件化(鉴权、限流、日志)
  • REST / gRPC
  • 多语言支持

适用场景

  • 多语言微服务
  • 对外开放 API 平台

6️⃣ Traefik

定位:云原生 Ingress / 网关

核心能力

  • 自动发现服务
  • Kubernetes 原生友好
  • 配置简单

适用场景

  • K8s 小中型集群
  • DevOps 驱动团队

7️⃣ 云厂商网关

  • 阿里云 API 网关
  • 腾讯云 API 网关
  • AWS API Gateway

适用场景

  • 不想自建
  • 强依赖云生态

Ⅱ. Spring Cloud Gateway

一、快速上手

① 创建网关项目

API 网关也是一个服务,所以这里单独创建一个 gateway 模块:

② 引入网关依赖

gateway 模块中引入网关以及相关依赖:

xml 复制代码
<!--网关-->
<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>
<!--负载均衡-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

③ 编写启动类

java 复制代码
@SpringBootApplication
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class,args);
    }
}

④ 添加Gateway的路由配置

创建 application.yml 文件,添加如下配置:

yaml 复制代码
server:
  port: 10020  # 网关端口

spring:
  application:
    name: gateway  # 应用名称
  cloud:
    nacos:
      discovery:
        server-addr: lirendada.art:8848  # Nacos地址
    gateway:
      routes:
        - id: order-service        # 路由id,随便起个名字,不重复即可
          uri: lb://order-service  # 目标服务地址
          predicates:              # 路由条件,这里配置路径匹配,匹配到/order/**、/feign/**的请求都转发到order-service服务
            - Path=/order/**,/feign/**
        - id: product-service
          uri: lb://product-service
          predicates:
            - Path=/product/**

配置字段说明:

  • id:自定义路由ID,保持唯一即可
  • uri:目标服务地址,支持普通 URI 及 lb://应用注册服务名称lb 表示负载均衡,使用 lb:// 方式表示从注册中心获取服务地址。
  • predicates:路由条件,根据匹配结果决定是否执行该请求路由,上述代码中,我们把符合 Path 规则的一切请求,都代理到 uri 参数指定的地址。

⑤ 测试

访问 http://127.0.0.1:10020/product/1001http://127.0.0.1:10020/order/1

二、Route Predicate Factories(路由断言工厂)

① Predicate

Predicate 是 Java8 提供的一个函数式编程接口,它接收一个参数并返回一个布尔值,用于条件过滤、请求参数的校验。其接口声明如下所示:

java 复制代码
@FunctionalInterface
public interface Predicate<T> {

    boolean test(T t);
    
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }
    
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }
    
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }
    
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
    
    @SuppressWarnings("unchecked")
    static <T> Predicate<T> not(Predicate<? super T> target) {
        Objects.requireNonNull(target);
        return (Predicate<T>)target.negate();
    }
}

代码演示:

  1. 定义一个 Predicate

    java 复制代码
       class StringPredicate implements Predicate<String> {
           @Override
           public boolean test(String str) {
               return str.isEmpty();
           }
       }
  2. 使用这个 Predicate

    java 复制代码
       public void t1() {
           Predicate p = new StringPredicate();
           System.out.println(p.test("hello"));
           System.out.println(p.test(""));
       }
       
       // 运行结果:
       false
       true
  3. Predicate 的其它写法:

    java 复制代码
       /**
        * 匿名内部类写法
        */
       @Test
       public void t2() {
           Predicate<String> p = new Predicate<String>() {
               @Override
               public boolean test(String s) {
                   return s.length() > 0;
               }
           };
           System.out.println(p.test("hello")); // true
           System.out.println(p.test(""));      // false
       }
       
       /**
        * lambda表达式写法
        */
       @Test
       public void t3() {
           Predicate<String> p = s -> s.length() > 0;
           System.out.println(p.test("hello")); // true
           System.out.println(p.test(""));      // false
       }

Predicate 的其它方法:

  • isEqual(Object targetRef):比较两个对象是否相等,参数可以为 Null
  • and(Predicate other):短路与操作,返回一个组成 Predicate
  • or(Predicate other):短路或操作,返回一个组成 Predicate
  • test(T t):传入一个 Predicate 参数,用来做判断
  • negate():返回表示此 Predicate 逻辑否定的 Predicate
方法 说明
Predicate and(Predicate<? super T> other) 条件A&&条件B 当前Predicate的test方法 && other的test方法,相当于进行两次判断
default Predicate negate() !条件A 对当前判断取非操作
default Predicate or(Predicate<? super T> other) 条件A||条件B 当前Predicate的test方法 || other的test方法
java 复制代码
/**
 * 非操作
 */
@Test
public void t4() {
    Predicate<String> p = s -> s.length() > 0;
    System.out.println(p.negate().test("hello")); // false
    System.out.println(p.negate().test(""));      // true
}

/**
 * and操作
 */
@Test
public void t5() {
    Predicate<String> p1 = s -> s.length() > 0;
    Predicate<String> p2 = s -> s.startsWith("l");
    System.out.println(p1.and(p2).test("hello")); // false
    System.out.println(p1.and(p2).test("liren")); // true
}

/**
 * or操作
 */
@Test
public void t6() {
    Predicate<String> p1 = s -> s.length() > 0;
    Predicate<String> p2 = s -> s.startsWith("l");
    System.out.println(p1.or(p2).test("hello")); // true
    System.out.println(p1.or(p2).test("liren")); // true
    System.out.println(p1.or(p2).test(""));      // false
}

② Route Predicate Factories

参考文档

在 Spring Cloud Gateway 中,Predicate 提供了路由规则的匹配机制:

yaml 复制代码
spring:
  cloud:
    gateway:
      routes: # 网关路由配置
        - id: product-service 
          uri: lb://product-service 
          predicates: 
            - Path=/product/**

我们在配置文件中写的断言规则只是字符串,这些字符串会被 Route Predicate Factory 读取并处理,转变为路由判断的条件。

比如例子中配置的 Path=/product/**,就是通过 Path 属性来匹配 URL 前缀是 /product 的请求。这个规则是由 org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory 实现的。

SpringCloudGateway 默认提供了很多 RoutePredicateFactory,这些 Predicate 会分别匹配 HTTP 请求的不同属性,并且多个 Predicate 可以通过 and 逻辑进行组合。

断言 作用
Path 路径匹配
Method HTTP 方法
Header 请求头
Query 请求参数
Cookie Cookie
Host 域名
After 指定时间后
Before 指定时间前
Between 时间区间
RemoteAddr 客户端 IP
Weight 权重
代码演示
  1. application.yml 中添加 Predicate 规则,新增一个 After 条件:

    yaml 复制代码
       spring:
         cloud:
           gateway:
             routes: # 网关路由配置
               - id: product-service 
                 uri: lb://product-service 
                 predicates: 
                   - Path=/product/**
                   - After=2025-12-13T14:08:33.643172900+08:00[Asia/Shanghai] # 请求时间为2025年12月13日之后
  2. 测试:访问 http://127.0.0.1:10020/product/1001,然后修改时间为 2026-01-01,再次访问

相关推荐
弹简特2 小时前
【JavaEE09-后端部分】SpringMVC04-SpringMVC第三大核心-处理响应和@RequestMapping详解
java·spring boot·spring·java-ee·tomcat
那我掉的头发算什么2 小时前
【图书管理系统】基于Spring全家桶的图书管理系统(下)
java·数据库·spring boot·后端·spring·mybatis
亓才孓12 小时前
[SpringIOC]NoSuchBeanDefinitionException
java·spring
前路不黑暗@13 小时前
Java项目:Java脚手架项目的文件服务(八)
java·开发语言·spring boot·学习·spring cloud·docker·maven
百锦再14 小时前
Java多线程编程全面解析:从原理到实战
java·开发语言·python·spring·kafka·tomcat·maven
清水白石00819 小时前
Python 缓存机制深度实战:从零打造带过期时间的记忆化装饰器
python·spring·缓存
亓才孓21 小时前
[Spring测试]TestRestTemplate
java·后端·spring
玹外之音21 小时前
Spring AI 结构化输出转换器实战:告别字符串解析,拥抱类型安全
spring·openai
爱跑步的程序员~1 天前
SpringBoot集成SpringAI与Ollama本地大模型
java·后端·spring·ai·llama·springai