再谈SpringCloud Gateway源码
- 一、整体请求流程
- 二、前置对象准备
- 1、实例化HandlerMapping
- 2、实例化Route
- 3、实例化WebHandler
- 三、实践业务扩展点
- 1、定义扩展Route对象
- 2、Filter能做什么
- 3、定义扩展Filter对象
- 4、定义父类Filter简化请求参数处理
前言:
之前有阅读过一次SpringCloud Gateway的源码,不过那时更多的是浮于表面,走了一遍流程。直到现在工作中真的遇到了基于SpringCloud Gateway的业务开发,才发现源码中很多机制还是不熟悉,于时又重新学习了一遍源码,并做此记录
前置知识:
- Reactive Streams&Reactor Core
- Spring WebFlux
- 浅谈Spring Cloud Gateway源码
一、整体请求流程
SpringCloud Gateway是基于Spring WebFlux完成请求的分发,整合SpringCloud Gateway后请求分发流程如下图:

二、前置对象准备
上面的流程更多的是描述当一个请求进来以后的分发流程,但是涉及到的一些对象都是在项目启动阶段完成的实例化
1、实例化HandlerMapping
在SpringCloud Gateway中会进行自动装配,自动创建一个RoutePredicateHandlerMapping,用于后续处理请求。当然我们也可以自定义,只要顺序在他的前面就可以(这也是常见自定义HandlerMapping的操作)


2、实例化Route
该部分逻辑涉及实例化对象较多
在HandlerMapping中,会涉及当前请求url与Route中定义的请求url匹配的逻辑,匹配命中则代表是网关请求,如果无法匹配命中则继续使用后续的handlerMapping判定,如当前项目上的创建的controller的接口的HandlerMapping。
1)RouteDefinitionLocator:实例化CompositeRouteDefinitionLocator
CompositeRouteDefinitionLocator可以看做是RouteDefinitionLocator的包装器,用于遍历访问所有RouteDefinitionLocator中定义的RouteDefinition。
在使用侧,我们只需要按照RouteDefinitionLocator中RouteDefinition的标准定义对象,即可完成自定义的添加


2)RouteLocator:实例化RouteDefinitionRouteLocator
这里会借助GatewayProperties、GatewayFilterFactory、RoutePredicateFactory,以及上一步创建的CompositeRouteDefinitionLocator(内部包含所有的RouteDefinition)来实例化该对象。

请注意,由于@Primary注解的存在,Gateway中使用的RouteLocator其实是下面的CachingRouteLocator,不过在CachingRouteLocator中,只是对所有的Route进行了缓存。
值得一提的是,这里的CompositeRouteLocator和前面的CompositeRouteDefinitionLocator的作用都是一致的,都是完成对所RouteLocator的包装,尽管示例代码中只有一个,但在真实的业务场景中,我们同样可以进行自定义扩展


注意:记住前面的RouteDefinitionLocator和RouteLocator,都是被Composite包装过一次,并且逻辑都是封装遍历。明白这个对于后续业务代码的执行流程至关重要。
3)Route:实例化Route
回顾最整体的请求流程,在获取HandlerMapping的时候,会调用到getHandlerInternal方法(org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping#getHandlerInternal。再往后走会调用到lookupRoute方法(org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping#lookupRoute)
即下图示例位置:

根据前面的解释,调用getRoutes的逻辑会遍历所有的RouteLocator,然后在RouteLocator内部又会遍历调用所有的RouteDefinitionLocator。此时就到了最关键的convertToRoute方法。该方法就会构建所有的断路器、拦截器(实例化Bean的时候有传递对应的Factory,在此处完成构建)


最终lookupRoute的返回值是Mono<Route>对象,即会返回匹配到的第一个Route,该对象就是我们预期命中的Route
3、实例化WebHandler
在getHandlerInternal方法(org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping#getHandlerInternal)中
,在命中Route路由后,只是将Route放置在了上下文中,此处真正返回的是在该HandlerMapping中定义的WebHandler对象

WebHandler对象同样是在自动装配类中实例化的,并且附带过滤器配置。

于是,我们可以得到结论,在最后传递到HandlerAdapter中执行handler请求的Object对象就是Gateway中定义的FilteringWebHandler(WebHandler)

最终在该WebHandler中,完成对应的执行逻辑。查看代码可以得出结论,这里的Filter主要分为两部分,一部分是从Route对象上获取的Filter(GatewayFilter),还有一部分是全局Filter(GlobalFilter),这部分在该WebHandler实例化的就传递进来了。将所有的Filter串联在一起,以一个责任链的形式完成业务逻辑

三、实践业务扩展点
1、定义扩展Route对象
我们可以自定义一个RouteDefinitionLocator类型的Bean,只要在调用该类的getRouteDefinitions方法时,返回我们自定义的Route,具体定义方式有很多,比如使用JSON,只需要最终解析出来的逻辑满足RouteDefinition规范即可
2、Filter能做什么
更多请参考官网文档
常见GlobalFilter:
- AdaptCachedBodyGlobalFilter:缓存
- NettyWriteResponseFilter:response写入
- ForwardPathFilter:转发请求
- ReactiveLoadBalancerClientFilter:负载均衡
- LoadBalancerServiceInstanceCookieFilter:根据cookie负载均衡
- NettyRoutingFilter:利用netty发起请求
常见GatewayFilter:
- AddRequestHeaderGatewayFilter:添加请求头
- PrefixPathGatewayFilter:切除path前缀
- RewritePathGatewayFilter:重写path
- RetryGatewayFilter:请求重试
- RemoveRequestHeaderGatewayFilter:移除请求头信息
- RequestRateLimiterGatewayFilter:限流
业务系统中常见的使用:
- 认证授权
- 基础参数校验
- 消息结构体的转化(XML转JSON)
- 业务参数级别的限流(尽管自带限流,但是功能过于简单,无法满足企业级系统的能力)
- 配置参数完成请求参数和返回结果的二次修改
- RPC的泛化调用
- 业务指标的监控埋点
- …
3、定义扩展Filter对象
如果我们希望这个Filter不用配置全局生效,就继承GlobalFilter;如果是希望在RouteDefinition中定义了才生效,则继承GatewayFilter。
补充:
- 针对GatewayFilter,我们要定义的有两部分,一个是Filter的定义AbstractGatewayFilterFactory类(Filter的Factory),需要实现apply方法用于实例化相应的GatewayFilter对象(可使用OrderedGatewayFilter对象进行包装);另一个是Filter的实现类,用于完成具体的业务逻辑。
- 执行流程为,在Route实例化的时候(convertToRoute),会根据Route中配置的Filter列表名字过滤(不修改则使用默认规则)出后所有的GatewayFilterFactory,然后调用GatewayFilterFactory的apply方法,此时就会回调到我们创建的GatewayFilter类的apply方法,此时只需要在apply方法中调用我们真正的业务Filter即可(尽管这里是Factory,但是可以参考适配器模式理解),示例代码如下:
@Component
public class RequestHandlerGatewayFilterFactory extends AbstractGatewayFilterFactory<RequestHandlerGatewayFilterConfig> {
@Autowired
RequestHandlerGatewayFilter filter;
public RequestHandlerGatewayFilterFactory() {
// 指定配置文件对象类型
super(RequestHandlerGatewayFilterConfig.class);
}
@Override
public GatewayFilter apply(RequestHandlerGatewayFilterConfig config) {
// 设置filter顺序
int order = Optional.ofNullable(config)
.map(BaseFilterConfig::getOrder)
.orElse(RouteOrderConstants.REQUEST_HANDLER_ORDER);
return new OrderedGatewayFilter((exchange, chain) -> {
// 配置文件内容传递
exchange.getAttributes().put(GatewayConstants.CACHE_REQUEST_REQUEST_HANDLER_CONFIG, config);
return filter.apply(exchange, chain);
}, order);
}
}
4、定义父类Filter简化请求参数处理
GatewayFilter的filter方法参数为ServerWebExchange对象,这并不方便我们在业务上对请求参数处理。我们可以编写一个抽象父类,用于屏蔽掉请求参数获取这部分,示例代码可参考:

public class CacheOutputMessage implements ReactiveHttpOutputMessage {
private final DataBufferFactory bufferFactory;
private final HttpHeaders httpHeaders;
private Flux<DataBuffer> body = Flux.error(new IllegalStateException("error"));
public CacheOutputMessage(ServerWebExchange exchange, HttpHeaders httpHeaders) {
this.bufferFactory = exchange.getResponse().bufferFactory();
this.httpHeaders = httpHeaders;
}
@Override
public void beforeCommit(Supplier<? extends Mono<Void>> action) {
}
@Override
public boolean isCommitted() {
return false;
}
@Override
public HttpHeaders getHeaders() {
return this.httpHeaders;
}
@Override
public DataBufferFactory bufferFactory() {
return this.bufferFactory;
}
public Flux<DataBuffer> getBody() {
return this.body;
}
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
this.body = Flux.from(body);
return Mono.empty();
}
@Override
public Mono<Void> writeAndFlushWith(
Publisher<? extends Publisher<? extends DataBuffer>> body) {
return writeWith(Flux.from(body)
.flatMap(p -> p));
}
@Override
public Mono<Void> setComplete() {
return writeWith(Flux.empty());
}
}
public class AbstractGatewayFilter {
/**
* 入口:FilterFactory的回调方法
*/
public Mono<Void> apply(ServerWebExchange exchange, GatewayFilterChain chain) {
// 如果已经完成请求,不再执行后续操作
if (ServerWebExchangeUtils.isAlreadyRouted(exchange)) {
return chain.filter(exchange);
}
// 1、修改请求体
ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
Mono<String> afterModifiedBody = serverRequest.bodyToMono(String.class)
.defaultIfEmpty("")
.flatMap(body -> {
BiFunction<ServerWebExchange, Mono<String>, Mono<String>> modifyBodyFun =
(funExchange, funBody) ->
// 修改请求内容
funBody.map(b -> getModifiedBody(b, exchange));
return modifyBodyFun.apply(exchange, Mono.just(body));
});
// 2、重新构造请求对象(含有请求头修改)
return prepareOutputMessage(exchange, afterModifiedBody)
.flatMap(outputMessage -> chain.filter(
exchange.mutate().request(
decorate(exchange, outputMessage.getHeaders(), outputMessage)
).build()
));
}
private Mono<CacheOutputMessage> prepareOutputMessage(ServerWebExchange exchange, Mono<String> modifiedBody) {
HttpHeaders headers = copyHeaders(exchange.getRequest().getHeaders());
BodyInserter<Mono<String>, ReactiveHttpOutputMessage> bodyInserter
= BodyInserters.fromPublisher(modifiedBody, String.class);
CacheOutputMessage outputMessage = new CacheOutputMessage(exchange, headers);
return bodyInserter.insert(outputMessage, new BodyInserterContext())
.thenReturn(outputMessage);
}
private ServerHttpRequestDecorator decorate(ServerWebExchange exchange,
HttpHeaders headers,
CacheOutputMessage outputMessage) {
return new ServerHttpRequestDecorator(exchange.getRequest()) {
@Override
public HttpHeaders getHeaders() {
return copyHeaders(getModifiedHeaders(exchange, super.getHeaders()));
}
@Override
public Flux<DataBuffer> getBody() {
return outputMessage.getBody();
}
};
}
/**
* 复制一份新的请求头
*/
private HttpHeaders copyHeaders(HttpHeaders headers) {
HttpHeaders newHeaders = new HttpHeaders();
if (headers == null) {
return newHeaders;
}
Map<String, List<String>> map = new HashMap<>();
headers.forEach((key, dataList) ->
map.put(key,
CollectionUtils.isEmpty(dataList) ? dataList : new ArrayList<>(dataList))
);
newHeaders.putAll(map);
return newHeaders;
}
/**
* 子类可重写此方法,用于修改请求头
*/
protected HttpHeaders getModifiedHeaders(ServerWebExchange exchange, HttpHeaders headers) {
return headers;
}
/**
* 子类可重写此方法,用于修改请求内容
*/
protected StringtModifiedBody(String body, ServerWebExchange exchange) {
return body;
}
}