统一服务入口-Gateway

目录

网关介绍

问题引出

[API 网关](#API 网关)

核心功能

常见网关实现

Zuul

[Spring Cloud Gateway](#Spring Cloud Gateway)

[Spring Cloud Gateway](#Spring Cloud Gateway)

快速使用

创建网关项目

引入网关依赖

启动类

[添加 Gateway 的路由配置](#添加 Gateway 的路由配置)

测试:

[Route Predicate Factories](#Route Predicate Factories)

Predicate

[Route Predicate Factories](#Route Predicate Factories)

代码示例

[Gateway Filter Factories(网关过滤工厂)](#Gateway Filter Factories(网关过滤工厂))

GatewayFilter

快速使用:

GatewayFilter

GlobalFilter

快速使用

过滤器执行顺序

自定义过滤器

[自定义 GatewayFilter](#自定义 GatewayFilter)

[定义 GatewayFilter](#定义 GatewayFilter)

[自定义 GlobalFilter](#自定义 GlobalFilter)

服务部署

完!


网关介绍

问题引出

前面的课程中,我们通过 Eureka,Nacos 解决了服务注册,服务发现的问题,使用 Spring Cloud LoadBalanced 解决了负载均衡问题,使用 OpenFeign 解决了远程调用问题。

但是,当前的所有微服务接口都是直接对外暴露的,可以直接通过外部进行访问。为了保证对外服务的安全性,服务端实现的微服务接口通常带有一定的权限校验。

由于使用了微服务模块,原本一个应用的多个模块被拆分成了多个应用,导致我们需要进行多次逻辑校验。当逻辑校验发生变化时,就需要改变多个应用

针对这个问题,常用的解决方式是使用 API 网关。

API 网关

API 网关(简称网关)也是一个服务,通常是后端服务的唯一入口。它的定义类似设计模式中的门面模式,可以理解为整个微服务架构的前台门面。所有访问微服务的外部客户端,都需要经过它来进行调度和过滤。

核心功能

  1. 权限控制:作为微服务的入口,对用户进行权限校验,如果权限校验失败则进行拦截。

  2. 动态路由:一切请求先经过网关,但网关不对业务进行处理,而是根据某种规则,把请求转发到某个微服务。

  3. 负载均衡:当路由的目标服务有多个的时候,还需要做负载均衡。

  4. 限流:请求流量过高的时候,按照网关中配置的微服务能够接收的流量进行放行,避免服务压力过大。

常见网关实现

实现网关的方式较多,技术方案较成熟,有很多开源产品,例如:Nginx,Kong,,Zuul,Spring Cloud Gateway 等。

Zuul

Spring Cloud Gateway

Spring Cloud Gateway

快速使用

在代码使用中,了解网关的功能作用。

创建网关项目

可以直接在前面的 openfeign 项目中继续完善。

引入网关依赖

启动类

添加 Gateway 的路由配置

在 application.yml 文件中,添加如下配置

配置字段说明:

1. id:路由规则的唯一标识符,用于区分不同的路由规则

2. uri:指定目标服务的地址。

lb:// 前缀表示使用负载均衡

product-service 是目标服务在注册中心的服务名称

3. predicates(断言):定义路由匹配条件,当请求满足所有断言条件时,路由才会到对应的 uri

Path 断言

基于路径的匹配。 /product/** 表示匹配所有以 /product 开头的请求

工作流程:

  1. 客户端请求对应 ip

  2. 网关匹配到 product-service 路由规则

  3. 从 Nacos 获取 product-service 的服务实例列表

  4. 通过负载均衡选择一个实例

  5. 将请求转发到选中的实例

测试:

启动 API 网关服务

  1. 通过网关服务访问 product-service

127.0.0.1:10030/product/1001

此时的 url 符合我们刚刚在 yml 文件中配置的 Path 断言:/product/** 规则,路由转发到 product-service:http://product-service/product/1001

访问后,我们可以观察网关服务的日志,看到网关服务从 Nacos 获取服务列表:

  1. 通过网关服务访问 order-service

127.0.0.1:10030/order/1

url 服务 yml 文件中配置的 Path 断言:/order/** 规则,路由转发到 order-service:http://order-service/product/1001

Route Predicate Factories

Predicate

Predicate 是 Java 8 提供的一个函数式编程接口,接收一个参数返回一个布尔值,用于条件过滤,请求参数的校验。

测试使用:

Predicate 的其他写法:

  1. 内置函数(匿名内部类):
  1. lambda 写法

有匿名内部类的写法,就也可以简化为 lambda 写法

再补充: s -> s.isEmpty() 也可以写成 String::isEmpty;


String::isEmpty 是一种直接方法引用。

对于一种"把接收到的参数直接当作调用者来执行某个方法"的情况,可以用方法引用来实现进一步的简写。

String::isEmpty 的工作流程:

这行代码 Predicate<String> predicate3 = String::isEmpty; 的意思是:

  1. :: 是方法引用的操作符

  2. String 是类名

  3. isEmpty 是该类的一个实例方法

编译器理解:


Predicate 的其他方法:

组合使用示例:

javascript 复制代码
List<String> list = Arrays.asList("Java", "Predicate", "Test", "API");

// 1. 创建一个 "条件A" (Predicate A)
Predicate<String> lengthCheck = s -> s.length() > 4;

// 2. 创建一个 "条件B" (Predicate B)
Predicate<String> startsWithJ = s -> s.startsWith("J");

// 3. 在 filter 中使用
// 筛选出长度大于4的
list.stream().filter(lengthCheck).forEach(System.out::println);
// 输出: Predicate

// 4. 组合使用:筛选出长度大于4,且以J开头的 (A && B)
list.stream().filter(lengthCheck.and(startsWithJ)).forEach(System.out::println);
// 输出: (无) 

// 5. 组合使用:筛选出长度大于4,或以J开头的 (A || B)
list.stream().filter(lengthCheck.or(startsWithJ)).forEach(System.out::println);
// 输出: Java, Predicate

静态方法:isEqual

签名:static <T> Predicate<T> isEqual(Object targetRef)

这是一个静态工厂方法,返回一个 Predicate。这个 Predicate 的作用是判断传入的参数是否等于 targetRef。让我们不必自己动手写 Lambda 表达式 ,而是直接调用一个方法来得到一个"现成的" Predicate 实例。

Route Predicate Factories

路由断言工厂,在 Spring Cloud Gateway 中,Predicate 提供了路由规则的匹配机制。

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

例如,前面举例中的快速使用,Path = /product/**,就是通过 Path 属性来匹配 URL 前缀是 /product 的请求~~

这个规则是由 org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory 实现的。

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

代码示例

  1. 添加 predicate 规则:
  1. 测试

访问:127.0.0.1:10030/order/1

返回 404

  1. 修改时间为 2024-01-01,再次访问

127.0.0.1:10030/order/1

正常返回结果

Gateway Filter Factories(网关过滤工厂)

前面的 Predicate 决定了请求由哪一个路由进行处理,如果在请求处理前后需要增加一些逻辑,这就是 Filter(过滤器)的作用范围。

Filter 分为两种类型:Pre 类型和 Post 类型。

Pre 类型过滤器 :路由处理之前执行(请求转发到后端服务之前执行),在 Pre 类型过滤器中可以做鉴权,限流等~

Post 类型过滤器:请求执行完毕后,将结果返回给客户端之前执行。

Spring Cloud Gateway 中内置了很多 Filter,用于拦截和链式处理 web 请求。比如权限校验,访问超时等等功能。

Spring Cloud Gateway 从作用范围 上,可以将 Filter 分为 GatewayFilter,GlobalFilter

**GateFilter:**应用到单个路由或者一个分组的路由上

**GlobalFilter:**应用到所有路由上,也就是对所有的请求生效

GatewayFilter

GatewayFilter 和 Predicate 类似,都是在 yml 配置文件中进行配置。

每个过滤器的逻辑都是固定的,比如 AddRequestParameterGatewayFilterFactory 只需要在配置文件中写 AddRequestParameter,就可以为所有的请求添加一个参数。


快速使用

在 application.yml 中添加 filter

在 product-service 中接收参数并进行打印

测试

重启 gateway 和 product-service 服务,访问请求,观察日志

127.0.0.1:10030/product/1001

控制台打印日志,接收到参数:zzz

GatewayFilter

Spring Cloud Gateway 提供了的 Filter 非常多,官方参考文档:qGatewayFilter Factories

前面的 filter 添加在指定路由下,所以只对当前路由生效,若需要对全部路由生效,可以使用

spring.cloud.gateway.default-filters

这个属性需要一个 filter 的列表

GlobalFilter

GlobalFilter 是 Spring Cloud Gateway 中的全局过滤器,它和 GatewayFilter 的作用是相同的。

GlobalFilter 通常用到所有的路由请求上,全局过滤器通常用于实现与安全性,性能监控,日志记录等相关的全局功能。

Spring Cloud Gateway 内置的全局过滤器也有很多,比如:

GatewayMetricsFilter: 网关指标,提供监控指标

ForwardRoutingFilter: 用于本地forword,请求不转发到下游服务器

LoadBalancerClientFilter: 针对下游服务,实现负载均衡.

官方文档:GlobalFiter

快速使用
  1. 引入依赖
  1. 添加配置

配置讲解:

  1. 测试

访问:127.0.0.1:10030/actuator 显示所有监控的信息链接

过滤器执行顺序

一个项目中,既有 GatewayFilter,又有 GlobalFilter 时,执行先后顺序:

请求路由后,网关会把当前项目中的 GatewayFilter 和 GlobalFilter 合并到一个过滤器链(集合)中,并进行排序,一次执行过滤器。

每一个过滤器都必须有一个 int 类型的 order 值,默认值为 0,表示该过滤的优先级。

order 越小,优先级越高,执行顺序就越靠前

Filter 通过实现 Order 接口,或者添加 @Order 注解来指定 order 的值。

Spring Cloud Gateway 提供的 Filter 由 Spring 指定。用户也可以自定义 Filter,由用户自行指定。

当过滤器的 order 值一样的时候,会按照:defaultFilter -> GatewayFilter -> GlobalFilter 的顺序执行

自定义过滤器

Spring Cloud Gateway 提供了过滤器的扩展,可以根据实际业务自定义过滤爱情,同样也是支持 GatewayFilter 和 GlobalFilter 两种

自定义 GatewayFilter

需要实现对应的接口 GatewayFilterFactory,SpringBoot 默认帮我们实现的抽象类是 AbstractGatewayFilterFactory,可以直接使用

定义 GatewayFilter

CustomGatewayFilter 继承 AbstractGatewayFilterFactory,实现 Ordered 接口

AbstractGatewayFilterFactory 需要一个配置类,来接收 yaml 传来的参数,它包含了过滤器所需的配置属性。在Spring Cloud Gateway 中,配置文件中的配置项慧自动映射到这个类中。例如:

CustomConfig 中有一个 name 属性,name 的值可以从 yaml 配置文件中获取并传递到过滤器中。

实现对应的方法,过滤器也需要 Spring 容器帮我们管理:

此外,还需要补充一个 CustomGatewayFilterFactory 的构造方法

在这个构造方法中,调用父类 AbstractGatewayFilterFactory 的构造方法,并传入了 CustomConfig.class 作为参数。

使用这个构造方法,可以使得 Spring Cloud Gateway 能够为过滤器解析配置,告诉 Spring 在 Yaml 文件中如何映射到自定义的配置类。

配置优先级:

然后实现 apply 方法,返回值为 GatewayFilter,new 一个 GatewayFilter 匿名内部类

在 apply 方法中,需要定义自定义过滤器的核心逻辑。apply 方法接收一个 CustomConfig 参数,表示该过滤器的配置。

ServerWebExchange:HTTP 请求-相应交互的契约,提供对 HTTP 请求和相应的访问,服务器端请求属性,请求示例,响应实例类等,类似 Context

其中有如下方法等:

GatewayFilterChain,过滤器链,用于调用下一个过滤器,chain.filter(exchange) 就可以执行过滤器链中的其他过滤器。

Mono:Reactor 核心类,数据流发布者,Mono 最多只触发一个时间,可以把 Mono 用在异步任务完成时发出通知。

Mono.fromRunnable:创建一个包含 Runnable 元素的数据流。then 方法表示过滤链执行完毕后进行的操作。

补充说明:

  1. 类名统一以 GatewayFilterFactory 结尾。因为默认情况下,过滤器中的 name 会采用该定义类的前缀。这里的 name = Custom(yml 配置文件中使用)

  2. apply 方法中,同时包含 Pre 和 Post 过滤,then 方法中是请求执行结束之后处理的。

  3. CustomConfig 是一个配置类,该类只有一个属性 name,和 yml 的配置对应。

  4. 该类需要交给 Spring 管理,所以需要加 @Service 注解。

  5. getOrder 表示该过滤器的优先级,值越大,优先级越低。


配置过滤器

​​​​​​​


测试:

重启服务,访问接口,观察日志。

127.0.0.1:10030/product/1001

自定义 GlobalFilter

GlobalFilter 实现比较简单,不需要额外的配置,只需要实现 GlobalFiler 接口,自动会过滤所有的 Filter

重启服务,访问接口,观察日志:

服务部署

  1. 修改数据库,Nacos 相关配置

  2. 对三个微服务进行打包

  3. 上传 jar 包到 Linux 服务器

  4. 启动 Nacos (启动前最好将 data 数据删除掉)

  5. 启动服务

测试,符合预期~

完!

相关推荐
ada7_2 小时前
LeetCode(python)——49.字母异位词分组
java·python·leetcode
DyLatte2 小时前
AI时代的工作和成长
java·后端·程序员
四维碎片2 小时前
【Qt】大数据量表格刷新优化--只刷新可见区域
开发语言·qt
青春不流名2 小时前
nginx
java
薛慕昭3 小时前
C语言核心技术深度解析:从内存管理到算法实现
c语言·开发语言·算法
.ZGR.3 小时前
第十六届蓝桥杯省赛 C 组——Java题解1(链表知识点)
java·算法·链表·蓝桥杯
一 乐3 小时前
流浪动物救助|流浪猫狗救助|基于Springboot+vue的流浪猫狗救助平台设计与实现(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·毕设
火星数据-Tina3 小时前
Python + WebSocket 实现实时体育比分系统(含数据库设计与前端演示)
开发语言·前端
Java水解3 小时前
Java基础------真实大厂面试题汇总(含答案)
java·后端·面试