本文会通过图文的方式由浅入深的描述 Spring Cloud Gateway (以下简称 gateway)的基本原理。
本文不涉及 gateway 的任何示例代码, 如有需要请参考官网 sample 。
阅读前, 需要读者提前掌握 gateway 的基本使用。至少要能读懂如下配置的含义:
spring:
cloud:
gateway:
routes:
- id: test_route
uri: lb://service-A
predicates:
- Path=/hello
filters:
- SetRequestHeader=X-Request-Red, Blue
以上便是 gateway 最基本的作用,它处理请求是逻辑是根据 配置的路由 对请求进行 预处理 和 转发
除此之外,还包括但不限于如下功能:
以上功能皆非本文讨论的重点内容,仅在此提及一下。
在讨论 gateway 工作原理之前, 我们先思考下, 如果让我们制作一个简单的网关应用, 实现方式有哪些。
根据上一章节末的描述可知, gateway 主要用于请求的转发处理。因此这里就涉及了网络通信的知识。
先简单翻译一下摘自 gateway 官网的描述:
SpringCloud Gateway 是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关。为了提升网关的性能,SpringCloud Gateway 是基于 WebFlux 框架实现的,而 WebFlux 框架底层则使用了高性能的 Reactor 模式通信框架 Netty。
然后我们结合 2.1 章节的分析, 可以将官网的描述成如下大白话:
Netty
是一款 出色 的网络通信框架。Reactor
模式通信框架 Netty
,所以可以直接拿来用。PS: 至于什么是响应式编程, 为什么 gateway 基于这些技术能够实现高性能, 这些不是本文探讨的内容,感兴趣的读者可以自行去了解。
那么, 如何理解 Spring WebFlux,我们暂且就把它当做 Spring WebMVC。一个 web 框架。
他们之间很重要的一个区别就在于 webmvc 我们一般会基于 tomcat
容器去完成底层的网络通信, 而 webflux 是基于 Netty
。
我们先来看下官网的描述:
从图中可以看出, 在 gateway 视角里,它在处理请求时, 划分成如下三大角色:
此时, 如果熟悉 Spring MVC 工作原理的可以看出,它和 Springmvc 的核心工作流程是类似的。
上面说到, gateway 底层还是基于 webflux。我们首先简单了解下 webflux 的工作原理, 然后延伸到 gateway 是如何基于 webflux 做扩展的。
以上是 webflux 处理请求的代码链路。我们着重看下标有颜色的类。
ReactorHttpHandlerAdapter
,他的作用是将 netty 的请求、响应转为 http 的请求、响应, 并交给后面的类处理。FilteringWebHandler
是 gateway 对 webflux 的扩展。简单总结:
如果没看懂, 可以看完下面的内容, 再回过头来看本章节。
Gateway 有三个比较核心的组件, 可以结合如下路由配置看一看:
spring:
cloud:
gateway:
routes:
- id: test_route
uri: lb://service-A
predicates:
- Path=/hello
filters:
- SetRequestHeader=X-Request-Red, Blue
Route
gateway 中可以配置多个 Route
。一个 Route
由路由 id,转发的 uri,多个 Predicates
以及多个 Filters
构成。处理请求时会按优先级排序,找到第一个满足所有 Predicates
的 Route。
Predicates
表示路由的匹配条件,可以用来匹配请求的各种属性,如请求路径、方法、header 等。一个 Route
可以包含多个 Predicates
,多个 Predicates
最终会合并成一个。
Filter
过滤器包括了处理请求和响应的逻辑,可以分为 pre 和 post 两个阶段。多个 Filter
在 pre 阶段会按优先级高到低顺序执行,post 阶段则是反向执行。gateway 中的 Filter 分为如下两种:
Filter
在 gateway 中只会有一个实例,会对所有的 Route
都生效。Filter
是针对 Route
进行配置的,不同的 Route
可以使用不同的参数,因此会创建不同的实例。围绕上述三个组件, gateway 又衍生出了一些其他组件。
具体作用我们会在下面一一说明。
接下来,我们通过对上图进行讲解, 来详细介绍各个组件在 gateway 中的作用。
首先, gateway 本质就是一个 Springboot
应用, 他是通过 webflux 框架处理请求和响应,而 webflux 底层是基于 Netty
。
GatewayAutoConfiguration
中配置的一些必要的组件 Bean
。 比如:
GatewayProperties
, 他里面保存了 gateway 的全部配置(其中就有路由配置信息)。GlobalFilter
, gateway 默认的一些全局过滤器。RouteDefinitionLocator
, 通过加载路由配置(比如读取 yaml 文件), 拿到 RouteDefinition
, 里面是对路由的定义。RouteLocator
, 负责组装 Route
对象, Route
对象中保存的是路由相关的信息。后续进行路由操作都是基于此对象。(请注意和 RouteDefinition
区分开)RoutePredicateHandlerMapping
和 org.springframework.cloud.gateway.handler.FilteringWebHandler
, 这两个类是对 webflux
中两个组件的扩展实现,后续会说到具体作用。webflux
经过一层层处理后,然后会去调用 HandlerMapping
接口,拿到对应的 Handler
。最后调用 Handler
的 handle
方法进行业务处理。HandlerMapping
和 Handler
两个接口,从而把处理请求的 活儿 从 webflux
手中接过来。Handler#handle
方法中,客户端发来的请求会经过上一步中过滤器链, 最终经过层层处理的请求会转发到对应服务中。RouteDefinition 定义了一个路由应该包含哪些匹配条件和过滤器,以及这些匹配条件和过滤器使用的参数, 它表示的是一个名词定义。在使用时 Gateway进行路由时, 会根据 RouteDefinition 对象提供的定义构造出 Route 对象,而 Route 里面提供了很多动作。
并且我们在前面提到: “一个 Route
可以包含多个 Predicates
,多个 Predicates
最终会合并成一个。因此我们可以看到,关于 Predicates,RouteDefinition 里面定义的是一个集合, 而 Route 中只是一个对象。
public class RouteDefinition {
// ...
private List<PredicateDefinition> predicates = new ArrayList<>();
}
public class Route implements Ordered {
// ....
private final AsyncPredicate<ServerWebExchange> predicate;
}
RouteLocator
接口中定义了获取路由配置的方法,RouteLocator 有不同的实现,对应了不同的定义路由的方式。
public interface RouteLocator {
Flux<Route> getRoutes();
}
前文中我们提到,定义路由的其中一个方式是通过 RouteLocatorBuilder
提供的 API 来构建具体的 Route
。
如下代码中定义了一个路由,其中包含了一个 path 匹配条件,以及一个添加响应 header 的 filter,请求转发的目标地址是 https://blog.csdn.net
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("route-id", r -> r.path("/test")
.filters(f -> f.addResponseHeader("X-TestHeader", "foobar"))
.uri("https://blog.csdn.net")
)
.build();
}
而 RouteDefinitionRouteLocator
是 RouteLocator
另一种常用的实现 。这种实现依赖于 RouteDefinitionLocator
来提供 RouteDefinition
,再由 RouteDefinition
构造路由。
CompositeRouteLocator
会把所有的 RouteLocator
的实现组合起来,再缓存到 CachingRouteLocator
中 。
因此当我们调用 getRoutes
方法获取路由集合时, 就会产生如下的调用关系:
RouteDefinitionLocator
接口定义了获取 RouteDefinition
的方法。
public interface RouteDefinitionLocator {
Flux<RouteDefinition> getRouteDefinitions();
}
前面我们多次提到 PropertiesRouteDefinitionLocator
可以通过解析 gateway 的配置文件中的路由配置拿到 RouteDefinition
对象集合
同上面的 RouteLocator
一样, 当 gateway 中有多个 RouteDefinitionLocator
实现时 , 同样会被 CompositeRouteDefinitionLocator
组合起来。
gateway 处理请求和响应的核心逻辑就在 Filter 中。gateway 本身实现提供了基础通用的过滤器,可以直接配置使用。 比如在请求前后, 分别添加请求头和响应头
我们再来看几个比较有意思的全局过滤器:
NettyRoutingFilter
在这个过滤器里面, 会发送转发请求到具体的 uri。
ReactiveLoadBalancerClientFilter
当 gateway 接入微服务时, 如果我们请求的服务存在多个实例,会在这里面进行负载均衡的处理。
本文通过图文结合的方式, 介绍了 Spring Cloud Gateway 的基本工作原理。
Spring Webflux
提供的扩展点,从而将请求与响应的工作转到自己手中。Spring Webflux
的底层是基于 Netty
和 Reactor
, 可以有效的提升网关的性能。另外,本文的不足之处包括但不限于如下几点:
当然, 后面如果有条件会对以上几点进行补充说明。