Spring Cloud Gateway(三):网关处理器
1、Spring Cloud Gateway 源码解析概述
API网关作为后端服务的统一入口,可提供请求路由、协议转换、安全认证、服务鉴权、流量控制、日志监控等服务。那么当请求到达网关时,网关都做了哪些处理以及怎么处理的呢?我们带着这些问题,顺着网关的处理流程,一步步进行源码阅读,一探究竟。
2、Spring Cloud Gateway 网关处理流程概述

1、请求发送到网关, DispatcherHandler 是HTTP请求的中央分发器,将请求匹配到响应的HandlerMapping;
2、请求与处理器之间有一个映射关系,网关将会对请求进行路由,handler会匹配到RoutePredicateHandlerMapping,以匹配到对应的Route
3、接着请求到达网关的web处理器,该WebHandler 代理了一系列网关过滤器和全局过滤器的实例,此时会对请求头或响应头进行处理
4、最后转发到具体的代理服务
3、Spring Cloud Gateway 初始化
当启动网关服务时,引入的Spring Cloud Gateway 的starter将会自动加载一些配置:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
# WebFlux 依赖检查配置类
org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration,\
# 网关核心自动配置类,配置路由规则、过滤器等
org.springframework.cloud.gateway.config.GatewayAutoConfiguration,\
# 客户端负载均衡自动配置类
org.springframework.cloud.gateway.config.GatewayLoadBalancerClientAutoConfiguration,\
# 网关指标自动配置类
org.springframework.cloud.gateway.config.GatewayMetricsAutoConfiguration,\
# redis 自动配置类
org.springframework.cloud.gateway.config.GatewayRedisAutoConfiguration,\
# 服务发现客户端自动配置类
org.springframework.cloud.gateway.discovery.GatewayDiscoveryClientAutoConfiguration
下面不会一一列出以上的配置,这里主要看一下设计网关属性的配置。GatewayProperties是网关配置中的核心配置属性类:
@ConfigurationProperties("spring.cloud.gateway")
@Validated
public class GatewayProperties {
//路由列表
@NotNull
@Valid
private List<RouteDefinition> routes = new ArrayList();
//默认过滤器
private List<FilterDefinition> defaultFilters = new ArrayList();
//流媒体类型
private List<MediaType> streamingMediaTypes;
public GatewayProperties() {
this.streamingMediaTypes = Arrays.asList(MediaType.TEXT_EVENT_STREAM, MediaType.APPLICATION_STREAM_JSON);
}
public List<RouteDefinition> getRoutes() {
return this.routes;
}
public void setRoutes(List<RouteDefinition> routes) {
this.routes = routes;
}
public List<FilterDefinition> getDefaultFilters() {
return this.defaultFilters;
}
public void setDefaultFilters(List<FilterDefinition> defaultFilters) {
this.defaultFilters = defaultFilters;
}
public List<MediaType> getStreamingMediaTypes() {
return this.streamingMediaTypes;
}
public void setStreamingMediaTypes(List<MediaType> streamingMediaTypes) {
this.streamingMediaTypes = streamingMediaTypes;
}
public String toString() {
return "GatewayProperties{routes=" + this.routes + ", defaultFilters=" + this.defaultFilters + ", streamingMediaTypes=" + this.streamingMediaTypes + '}';
}
}
GatewayProperties 有三个属性,分别是路由列表(对应路由定义对象RouteDefinition)、默认过滤器列表(对应过滤器对象FilterDefinition)、流媒体类型列表(对应流媒体对象MediaType)
4、网关处理器
当请求到达网关时,会有各种web处理器对请求进行匹配和处理,下面我们将会对主要的几个web处理器进行讲解

graph LR
DispatcherHandler -->RoutePredicateHandlerMapping
RoutePredicateHandlerMapping-->FilteringWebHandler
FilteringWebHandler-->DefaultGatewayFilterChain
4.1、请求分发器 DispatcherHandler
Spring Cloud Gateway 引入了Spring WebFlux, DispatcherHandler 是 请求分发处理器,是网关请求的入口。之前的项目中引入的是 Spring MVC,它的分发 处理器是 DispatcherServlet。下面看一下网关收到请求后是如何处理的:
public class DispatcherHandler implements WebHandler, ApplicationContextAware {
private static final Exception HANDLER_NOT_FOUND_EXCEPTION;
private static final Log logger;
@Nullable
private List<HandlerMapping> handlerMappings;
@Nullable
private List<HandlerAdapter> handlerAdapters;
@Nullable
private List<HandlerResultHandler> resultHandlers;
public DispatcherHandler() {
}
public DispatcherHandler(ApplicationContext applicationContext) {
this.initStrategies(applicationContext);
}
@Nullable
public final List<HandlerMapping> getHandlerMappings() {
return this.handlerMappings;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.initStrategies(applicationContext);
}
//根据请求匹配对应的出列器
public Mono<Void> handle(ServerWebExchange exchange) {
if (logger.isDebugEnabled()) {
ServerHttpRequest request = exchange.getRequest();
logger.debug("Processing " + request.getMethodValue() + " request for [" + request.getURI() + "]");
}
return this.handlerMappings == null ? Mono.error(HANDLER_NOT_FOUND_EXCEPTION) : Flux.fromIterable(this.handlerMappings).concatMap((mapping) -> {
return mapping.getHandler(exchange);
}).next().switchIfEmpty(Mono.error(HANDLER_NOT_FOUND_EXCEPTION)).flatMap((handler) -> {
return this.invokeHandler(exchange, handler);
}).flatMap((result) -> {
return this.handleResult(exchange, result);
});
}
private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
if (this.handlerAdapters != null) {
for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
if (handlerAdapter.supports(handler)) {
return handlerAdapter.handle(exchange, handler);
}
}
}
return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
}
private Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
return getResultHandler(result).handleResult(exchange, result)
.onErrorResume(ex -> result.applyExceptionHandler(ex).flatMap(exceptionResult ->
getResultHandler(exceptionResult).handleResult(exchange, exceptionResult)));
}
private HandlerResultHandler getResultHandler(HandlerResult handlerResult) {
if (this.resultHandlers != null) {
for (HandlerResultHandler resultHandler : this.resultHandlers) {
if (resultHandler.supports(handlerResult)) {
return resultHandler;
}
}
}
throw new IllegalStateException("No HandlerResultHandler for " + handlerResult.getReturnValue());
}
}
DispatcherHandler 实现了 WebHandler 接口,WebHandler 接口是用来处理 Web请求的。在DispatcherHandler 的构造函数中会初始化 HandlerMapping,核心 处理 的方法是 handle( ServerWebExchange exchange), 而 HandlerMapping 是一个定义 了请求与处理器对象映射的接口且有多个实现类,如 ControllerEndpointHandlerMapping 和 RouterFunctionMapping。
invokeHandler 方法调用相应的 WebHandler,获取该WebHandler对应的适配器。
4.2、路由断言处理器 RoutePredicateHandlerMapping
RoutePredicateHandlerMapping 用于匹配具体的Route,并返回处理 Route 的 FilteringWebHandler
public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
private final FilteringWebHandler webHandler;
private final RouteLocator routeLocator;
public RoutePredicateHandlerMapping(FilteringWebHandler webHandler, RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties) {
this.webHandler = webHandler;
this.routeLocator = routeLocator;
this.setOrder(1);
this.setCorsConfigurations(globalCorsProperties.getCorsConfigurations());
}
................................
}
RoutePredicateHandlerMapping 的构造函数接受两个参数,
FilteringWebHandler 网关过滤器 和 RouteLocator 路由定位器, setOrder( 1) 用于设置该对象初始化的优先级。
Spring Cloud Gateway 的 GatewayWebfluxEndpoint 提供的 HTTP API 不需要经过 网关转发,它通过 RequestMappingHandlerMapping 进行请求匹配处理,因此需要将 RoutePredicateHandlerMapping 的优先级设置为 低于RequestMappingHandlerMapping。
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
//设置网关处理器为 RoutePredicateHandlerMapping
exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_HANDLER_MAPPER_ATTR, this.getClass().getSimpleName());
return this.lookupRoute(exchange).flatMap((r) -> {
exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Mapping [" + this.getExchangeDesc(exchange) + "] to " + r);
}
exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR, r);
return Mono.just(this.webHandler);
}).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No RouteDefinition found for [" + this.getExchangeDesc(exchange) + "]");
}
})));
}
//路由顺序匹配
protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
return this.routeLocator.getRoutes().concatMap((route) -> {
return Mono.just(route).filterWhen((r) -> {
exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
return (Publisher)r.getPredicate().apply(exchange);
}).doOnError((e) -> {
this.logger.error("Error applying predicate for route: " + route.getId(), e);
}).onErrorResume((e) -> {
return Mono.empty();
});
}).next().map((route) -> {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Route matched: " + route.getId());
}
//校验路由有效性
this.validateRoute(route, exchange);
return route;
});
}
以上为获取 handler 的方法,匹配请求的Route,并返回处理 Route的过滤器 FilteringWebHandler。
首先设置GATEWAY_ HANDLER_ MAPPER_ ATTR 为 RoutePredicateHandlerMapping 的类名
然后顺序匹配对应的 Route,RouteLocator 接口获取网关中定义的路由,并根据请求信息与路由定义的断言按照优先级匹配。
最后找到匹配的Route,并返回响应的处理器。
4.3、过滤器处理器 FilteringWebHandler
FilteringWebHandler 通过创建所请求 Route 对应的 GatewayFilterChain, 在网关进行过滤处理
public class FilteringWebHandler implements WebHandler {
protected static final Log logger = LogFactory.getLog(FilteringWebHandler.class);
private final List<GatewayFilter> globalFilters;
public FilteringWebHandler(List<GlobalFilter> globalFilters) {
this.globalFilters = loadFilters(globalFilters);
}
private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
return (List)filters.stream().map((filter) -> {
//适配 GatewayFilter
FilteringWebHandler.GatewayFilterAdapter gatewayFilter = new FilteringWebHandler.GatewayFilterAdapter(filter);
//是否实现了 Ordered,如果实现了,则返回OrderedGatewayFilter
if (filter instanceof Ordered) {
int order = ((Ordered)filter).getOrder();
return new OrderedGatewayFilter(gatewayFilter, order);
} else {
return gatewayFilter;
}
}).collect(Collectors.toList());
}
public Mono<Void> handle(ServerWebExchange exchange) {
Route route = (Route)exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
List<GatewayFilter> gatewayFilters = route.getFilters();
List<GatewayFilter> combined = new ArrayList(this.globalFilters);
//加入全局过滤器
combined.addAll(gatewayFilters);
//过滤器排序
AnnotationAwareOrderComparator.sort(combined);
logger.debug("Sorted gatewayFilterFactories: " + combined);
//按照优先级对请求进行过滤
return (new FilteringWebHandler.DefaultGatewayFilterChain(combined)).filter(exchange);
}
}
全局变量 globalFilters 是Spring Cloud Gateway 定义的全局过滤器,构造函数通过传入全局过滤器,对过滤器进行适配。因为过滤器有优先级,loadFilters 该方法主要是判断过滤器是否实现了 Ordered 接口,如果实现了则返回OrderedGatewayFilter,否则返回适配的过滤器。最后将适配的过滤器加入全局过滤器,并对过滤器进行排序,根据优先级对请求进行处理。
4.4、生成过滤器链
FilteringWebHandler 内部静态类 DefaultGatewayFilterChain
private static class DefaultGatewayFilterChain implements GatewayFilterChain {
private final int index;
private final List<GatewayFilter> filters;
public DefaultGatewayFilterChain(List<GatewayFilter> filters) {
this.filters = filters;
this.index = 0;
}
private DefaultGatewayFilterChain(FilteringWebHandler.DefaultGatewayFilterChain parent, int index) {
this.filters = parent.getFilters();
this.index = index;
}
public List<GatewayFilter> getFilters() {
return this.filters;
}
public Mono<Void> filter(ServerWebExchange exchange) {
return Mono.defer(() -> {
if (this.index < this.filters.size()) {
GatewayFilter filter = (GatewayFilter)this.filters.get(this.index);
FilteringWebHandler.DefaultGatewayFilterChain chain = new FilteringWebHandler.DefaultGatewayFilterChain(this, this.index + 1);
return filter.filter(exchange, chain);
} else {
return Mono.empty();
}
});
}
}
FilteringWebHandler 的 handle 方法,首先获取请求对应的路由过滤器和全局过滤器,并将两者合并。
然后对过滤器进行排序。
最后按照优先级生成过滤器链,对请求进行过滤处理。
过滤器链的生成是通过内部静态类 DefaultGatewayFilterChain 实现的,该类实现了GatewayFilterChain 接口,最后对请求按照过滤器优先级进行过滤。
Spring Cloud Gateway(三):网关处理器的更多相关文章
- Spring Cloud Gateway 服务网关快速上手
Spring Cloud Gateway 服务网关 API 主流网关有NGINX.ZUUL.Spring Cloud Gateway.Linkerd等:Spring Cloud Gateway构建于 ...
- Spring Cloud Gateway服务网关
原文:https://www.cnblogs.com/ityouknow/p/10141740.html Spring 官方最终还是按捺不住推出了自己的网关组件:Spring Cloud Gatewa ...
- Spring Cloud gateway 三 自定义过滤器GatewayFilter
之前zuul 网关介绍.他有过滤器周期是四种,也是四种类型的过滤器.而gateway 只有俩种过滤器:"pre" 和 "post". PRE: 这种过滤器在请求 ...
- Spring Cloud gateway 网关四 动态路由
微服务当前这么火爆的程度,如果不能学会一种微服务框架技术.怎么能升职加薪,增加简历的筹码?spring cloud 和 Dubbo 需要单独学习.说没有时间?没有精力?要学俩个框架?而Spring C ...
- spring Cloud网关之Spring Cloud Gateway
Spring Cloud Gateway是什么?(官网地址:https://cloud.spring.io/spring-cloud-gateway/reference/html/) Spring C ...
- Spring Cloud gateway 五 Sentinel整合
微服务当前这么火爆的程度,如果不能学会一种微服务框架技术.怎么能升职加薪,增加简历的筹码?spring cloud 和 Dubbo 需要单独学习.说没有时间?没有精力?要学俩个框架?而Spring C ...
- Spring Cloud gateway 六 Sentinel nacos存储动态刷新
微服务当前这么火爆的程度,如果不能学会一种微服务框架技术.怎么能升职加薪,增加简历的筹码?spring cloud 和 Dubbo 需要单独学习.说没有时间?没有精力?要学俩个框架?而Spring C ...
- 熬夜肝了这篇Spring Cloud Gateway的功能及综合使用
前言 SpringCloud 是微服务中的翘楚,最佳的落地方案. Spring Cloud Gateway 是 Spring Cloud 新推出的网关框架,之前是 Netflix Zuul.网关通常在 ...
- 网关服务Spring Cloud Gateway(三)
上篇文章介绍了 Gataway 和注册中心的使用,以及 Gataway 中 Filter 的基本使用,这篇文章我们将继续介绍 Filter 的一些常用功能. 修改请求路径的过滤器 StripPrefi ...
随机推荐
- 【SQL Server高可用性】数据库复制:SQL Server 2008R2中通过数据库复制,把A表的数据复制到B表
原文:[SQL Server高可用性]数据库复制:SQL Server 2008R2中通过数据库复制,把A表的数据复制到B表 经常在论坛中看到有人问数据同步的技术,如果只是同步少量的表,那么可以考虑使 ...
- MVC自定定义扩展点之ActionNameSelectorAttribute+ActionFilterAttribute 在浏览器中打开pdf文档
仅仅演示 了ASP.MVC 5 下为了在在浏览器中打开pdf文档的实现方式之一,借此理解下自定义ActionNameSelectorAttribute+ActionFilterAttribute 类的 ...
- 【转载】 C#中使用Count方法获取List集合中符合条件的个数
很多时候操作List集合的过程中,我们需要根据特定的查询条件,获取List集合中有多少个实体对象符合查询条件,例如一批产品的对象List集合,如果这批产品的不合格数量大于10则重点备注.在C#中可以自 ...
- 转载 AI-Talking 图算法
https://mp.weixin.qq.com/s/2XRgJr-ydxHA3JxAZ_5HeA 图算法在风控业务的实践 直播行业中有很多业务风控问题,比如说批量注册.刷热度.垃圾信息以及薅羊毛等. ...
- sed 删除文本中的内容
删除命令对照表 练习例子 删除/etc/passwd中的第15行 sed -i '1d' passwd 删除/etc/passwd中的8行到14行的所有内容 sed -i '8,14d' passwd ...
- Mysql 中完善的帮助命令
Mysql 中完善的帮助命令 Mysql 中的帮助系统很完善,很多操作都可以通过命令行直接获得帮助,如下示例: Mysql 命令行帮助 [root@mysql1 mydata1]# mysql -S ...
- python之匿名函数、递归与二分法
一.匿名函数 什么是匿名函数? 顾名思义就是没有名字的函数,在我们声明一个函数时会想起个什么函数名好,这个问题我想有时候会困惑大家的吧? def func(): #正常函数声明 pass prin ...
- Tkinter关于新建窗口内Entry无法获取值(值全为空)的解决办法
最近在做Python的课程作业,遇到一个问题,描述如下: 使用Python内置的Tkinter模块进行GUI编程 给一个按钮(或菜单)绑定事件,打开一个新窗口,新窗口内有Entry若干,通过textv ...
- 基于Java+Selenium的WebUI自动化测试框架(六)---浏览器初始化
本篇我们来讨论,如何写一个浏览器初始化的类.在写之前,先思考一下,我们需要一个什么样的初始化? 先来看看使用原生的Java + selenium是怎么做的.(以firefox为例) System.se ...
- android:duplicateParentState属性使用场景
对于这个属性的使用也是在偶然的时候发现的,之前从未使用它,所以有必要阐述一下它的用法,什么场景会要用它这个属性,在我不知道之前这个属性之前,也同样能实现效果,但是当我知道它的存在之后,我肯定在某种场景 ...