夏普|Spring Cloud Gateway一次请求调用源码解析( 二 )


http handler做的事情第一是将request 和 response转为一个exchange , 这个exchange非常核心 , 是各个filter之间参数流转的载体 , 该类包含request、response、attributes(扩展字段) , 接着做的事情就是web filter链的执行 , 其中的逻辑主要是监控 。

其中WebfilterChainParoxy 又会引出新的一条filter链 , 主要是安全、日志、认证相关的逻辑 , 由此可见Spring Cloud Gateway的过滤器设计是层层嵌套 , 扩展性很强 。

3 寻找路由规则
核心类是RoutePredicateHandlerMapping , 逻辑也非常简单 , 就是把所有的route规则的predicate遍历一遍看哪个predicate能够命中 , 核心代码是:
return this.routeLocator.getRoutes() .filter(route -{ ... return route.getPredicate().test(exchange); ) 因为我这里用的是path进行过滤 , 所以背后的逻辑是PathRoutePredicateFactory来完成的 , 除了PathRoutePredicateFactory还有很多predicate规则 。

这些路由规则都能从官方文档上找到影子 。

4 核心过滤器链执行
找到路由规则后下一步就是执行了 , 这里的核心类是FilteringWebHandler , 其中的源码为:

做的事情很简单:









【夏普|Spring Cloud Gateway一次请求调用源码解析】
获取route级别的过滤器 获取全局过滤器 两种过滤器放在一起并根据order进行排序 执行过滤器链 因为我的配置里包含了一个添加请求参数的逻辑 , 所以红线箭头处就是我配置的gateway filter名为 AddRequestParameterGatewayFilterFactory , 其余全是Gloabl Filter , 这些过滤器的功能主要是url解析 , 请求转发 , 响应回写等逻辑 , 因为我们这里用的是forward schema , 所以请求转发会由ForwardRoutingFilter进行执行 。5 请求转发 ForwardRoutingFilter做的事情也很简单 , 直接复用了spring mvc的能力 , 将请求提交给dispatcherHandler进行处理 , dispatcherHandler会根据path前缀找到需要目标处理器执行逻辑 。@Overridepublic MonoVoidfilter(ServerWebExchange exchange GatewayFilterChain chain) { URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR); String scheme = requestUrl.getScheme(); if (isAlreadyRouted(exchange) || !\"forward\".equals(scheme)) { return chain.filter(exchange);setAlreadyRouted(exchange); //TODO: translate url? if (log.isTraceEnabled()) { log.trace(\"Forwarding to URI: \"+requestUrl);return this.dispatcherHandler.handle(exchange); 6 响应回写 响应回写的核心类是NettyWriteResponseFilter , 但是大家可以注意到执行器链中NettyWriteResponseFilter的排序是在最前面的 , 按道理这种响应处理的类应该是在靠后才对 , 这里的设计比较巧妙 。 大家可以看到chain.filter(exchange).then() , 意思就是执行到我的时候直接跳过下一个 , 等后面的过滤器都执行完后才执行这段逻辑 , 这种行为控制的方法值得学习 。@Overridepublic MonoVoidfilter(ServerWebExchange exchange GatewayFilterChain chain) { // NOTICE: nothing in \"pre\" filter stage as CLIENT_RESPONSE_ATTR is not added // until the WebHandler is run return chain.filter(exchange).then(Mono.defer(() -{ HttpClientResponse clientResponse = exchange.getAttribute(CLIENT_RESPONSE_ATTR); if (clientResponse == null) { return Mono.empty();log.trace(\"NettyWriteResponseFilter start\"); ServerHttpResponse response = exchange.getResponse(); NettyDataBufferFactory factory = (NettyDataBufferFactory) response.bufferFactory(); //TODO: what if it's not netty final FluxNettyDataBufferbody = clientResponse.receive() .retain() //TODO: needed? .map(factory::wrap); MediaType contentType = response.getHeaders().getContentType(); return (isStreamingMediaType(contentType) ? response.writeAndFlushWith(body.map(Flux::just)) : response.writeWith(body)); )); 四 总结 整体读完Spring Cloud Gateway请求流程代码后 , 有几点感受: 过滤器是Spring Cloud Gateway最核心的设计 , 甚至于可以夸张说Spring Cloud Gateway是一个过滤器链执行框架而不是一个API网关 , 因为API网关实际的请求转发、请求响应回写都是在过滤器中做的 , 这些是Spring Cloud Gateway感知不到的逻辑 。Spring Cloud Gateway路由规则获取的模块具备优化的空间 , 因为是循环遍历进行获取的 , 如果每个route规则较多 , predicate规则较复杂 , 就可以考虑用map进行优化了 , 当日route规则 , predicate规则也不会很复杂 , 兼顾到代码的可读性 , 当前方式也没有什么问题 。作为API网关框架 , 内置了非常多的过滤器 , 如果有过滤器的卸载功能可能会更好 , 用户可用根据实际情况卸载不必要的功能 , 背后减少的逻辑开销 , 在调用量极大的API网关场景 , 收益也会很可观 。作者 | 寻筝 原文链接:https://developer.aliyun.com/article/804348?utm_content=g_1000308318 本文为阿里云原创内容 , 未经允许不得转载 。