【深入理解SpringCloud微服务】Gateway源码解析
- Gateway原理复习
- 源码解析
-
- [DispatcherHandler#handle(ServerWebExchange exchange)](#handle(ServerWebExchange exchange))
- [RoutePredicateHandlerMapping#getHandlerInternal(ServerWebExchange exchange)](#getHandlerInternal(ServerWebExchange exchange))
- [FilteringWebHandler#handle(ServerWebExchange exchange)](#handle(ServerWebExchange exchange))
- 几个核心的过滤器
-
- [LoadBalancerClientFilter#filter(ServerWebExchange exchange, GatewayFilterChain chain)](#filter(ServerWebExchange exchange, GatewayFilterChain chain))
- [NettyRoutingFilter#filter(ServerWebExchange exchange, GatewayFilterChain chain)](#filter(ServerWebExchange exchange, GatewayFilterChain chain))
Gateway原理复习

Gateway 基于Spring-WebFlux,实现了WebFlux的两个核心组件HandleMapping和WebHandler。
- 首先HandleMapping会加载路由配置,并调用路由配置中的断言函数进行匹配,如果匹配成功,则使用该路由规则。
- WebHandler 会把路由配置中指定的过滤器(GatewayFilter )和全局过滤器(GlobalFilter)组装成过滤器链,然后调用过滤器链进行请求处理。
源码解析
DispatcherHandler#handle(ServerWebExchange exchange)
spring-cloud-gateway 是基于spring-webflu 的,而spring-webflux通过netty 接收请求,当接收到请求时,会调用 DispatcherHandler#handle(ServerWebExchange exchange) 该方法进行处理。
DispatcherHandler#handle(ServerWebExchange exchange)
java
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
if (this.handlerMappings == null) {
return createNotFoundError();
}
return Flux.fromIterable(this.handlerMappings)
// 通过HandlerMapping获取WebHandler
.concatMap(mapping -> mapping.getHandler(exchange))
.next()
.switchIfEmpty(createNotFoundError())
// 调用WebHandler进行请求处理
.flatMap(handler -> invokeHandler(exchange, handler))
// 处理返回结果
.flatMap(result -> handleResult(exchange, result));
}

".concatMap(mapping -> mapping.getHandler(exchange))" 这行代码会调用到Gateway的RoutePredicateHandlerMapping的**getHandlerInternal()**方法,返回一个FilteringWebHandler。
然后 ".flatMap(handler -> invokeHandler(exchange, handler))" 这行代码会调用到RoutePredicateHandlerMapping 的handle() 方法。
我们下面分别看一下RoutePredicateHandlerMapping的getHandlerInternal方法和RoutePredicateHandlerMapping的handle方法。
RoutePredicateHandlerMapping#getHandlerInternal(ServerWebExchange exchange)
java
@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
...
//寻找Route
//首先获取配置文件里面的routes配置,得到RouteDefinition集合
//然后RouteDefinition转换成Route,得到Route集合
//然后根据Route中的Predicate#apply(exchange)进行过滤
//返回匹配的一个Route
return lookupRoute(exchange)
.flatMap((Function<Route, Mono<?>>) r -> {
...
//绑定Route到请求上下文exchange中,gatewayRoute -> Route
exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
//返回一个FilteringWebHandler
return Mono.just(webHandler);
}).switchIfEmpty(...);
}
getHandlerInternal() 方法首先调用lookupRoute(exchange) 方法寻找匹配的route 。然后把匹配到的route绑定到ServerWebExchange 对象中,最后返回一个FilteringWebHandler。

RoutePredicateHandlerMapping#lookupRoute(ServerWebExchange exchange)
java
protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
// 拿到配置文件中的routes配置信息 RouteDefinition
// 然后转换成Route对象,然后一个Route集合
return this.routeLocator.getRoutes()
// 遍历route集合
.concatMap(route -> Mono.just(route).filterWhen(r -> {
...
//r.getPredicate()获取到Route中的谓词Predicate
//调用Predicate#apply方法判断是否符合谓词的条件
return r.getPredicate().apply(exchange);
})
.doOnError(...)
.onErrorResume(...)
.next()
.map(...);
}
lookupRoute(exchange)方法首先调用routeLocator.getRoutes() 方法获取到Route 集合,然后遍历Route集合,调用route中的Predicate进行匹配,然后返回匹配的route。

RouteDefinitionRouteLocator#getRoutes()
java
@Override
public Flux<Route> getRoutes() {
//getRouteDefinitions():获取路由定义信息
//this::convertToRoute:转换所有的RouteDefinition为Route
return this.routeDefinitionLocator.getRouteDefinitions().map(this::convertToRoute)
.map(...);
}
getRoutes() 方法调用getRouteDefinitions() 获取到所有的RouteDefinition,然后将其转换成Route。

FilteringWebHandler#handle(ServerWebExchange exchange)
java
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
//从请求上下文获取Route
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
//从Route获取所有的GatewayFilter
List<GatewayFilter> gatewayFilters = route.getFilters();
//添加全局过滤器到一个新的集合中
List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
combined.addAll(gatewayFilters); //加入普通过滤器
// 对过滤器进行排序
AnnotationAwareOrderComparator.sort(combined);
...
//构建过滤器链,调用chain的filter(exchage)进行处理
return new DefaultGatewayFilterChain(combined).filter(exchange);
}
handle() 方法做的事情就是组装过滤器链,并调用过滤器链进行处理。

下面我们看看几个核心的过滤器。
几个核心的过滤器
LoadBalancerClientFilter#filter(ServerWebExchange exchange, GatewayFilterChain chain)
java
@Override
@SuppressWarnings("Duplicates")
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
String schemePrefix = exchange.getAttribute(GATEWAY_SCHEME_PREFIX_ATTR);
...
//通过ribbon去nacos获取对应微服务名的实例列表
//通过负载均衡算法选取一个
final ServiceInstance instance = choose(exchange);
...
URI uri = exchange.getRequest().getURI();
...
//通过LoadBalancerClient的reconstructURI方法重新组装url
URI requestUrl = loadBalancer.reconstructURI(
new DelegatingServiceInstance(instance, overrideScheme), uri);
//重写后的url重新绑定到上下文的gateWayRequestUrl参数
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
//调用下一个filter
return chain.filter(exchange);
}
LoadBalancerClientFilter 的作用就是利用ribbon的负载均衡机制选出一个实例,然后根据负载均衡的结果重写url。

NettyRoutingFilter#filter(ServerWebExchange exchange, GatewayFilterChain chain)
java
@Override
@SuppressWarnings("Duplicates")
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//从上下文获取到重写后的url
URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);
...
// 请求对象
ServerHttpRequest request = exchange.getRequest();
// 请求方法
final HttpMethod method = HttpMethod.valueOf(request.getMethodValue());
// 请求url
final String url = requestUrl.toASCIIString();
HttpHeaders filtered = filterRequest(getHeadersFilters(), exchange);
final DefaultHttpHeaders httpHeaders = new DefaultHttpHeaders();
filtered.forEach(httpHeaders::set);
...
// 利用Netty的HttpClient向后端微服务发起请求
Flux<HttpClientResponse> responseFlux = this.httpClient
.chunkedTransfer(chunkedTransfer).request(method).uri(url)
.send((req, nettyOutbound) -> {
req.headers(httpHeaders);
...
return nettyOutbound.options(NettyPipeline.SendOptions::flushOnEach)
.send(request.getBody()
.map(dataBuffer -> ((NettyDataBuffer) dataBuffer)
.getNativeBuffer()));
})
// 处理后端微服务的返回结果
.responseConnection((res, connection) -> {
exchange.getAttributes().put(CLIENT_RESPONSE_ATTR, res);
exchange.getAttributes().put(CLIENT_RESPONSE_CONN_ATTR, connection);
ServerHttpResponse response = exchange.getResponse();
HttpHeaders headers = new HttpHeaders();
// 后端微服务返回的响应头
res.responseHeaders().forEach(
entry -> headers.add(entry.getKey(), entry.getValue()));
...
// 后端微服务返回的状态码
HttpStatus status = HttpStatus.resolve(res.status().code());
if (status != null) {
response.setStatusCode(status);
}
else if (response instanceof AbstractServerHttpResponse) {
...
}
else {...}
HttpHeaders filteredResponseHeaders = HttpHeadersFilter.filter(
getHeadersFilters(), headers, exchange, Type.RESPONSE);
...
response.getHeaders().putAll(filteredResponseHeaders);
return Mono.just(res);
});
...
return responseFlux.then(chain.filter(exchange));
}
NettyRoutingFilter 的作用就是获取到LoadBalancerClientFilter 重写后的url,利用Netty 的HttpClient向后端微服务发起请求,然后获取到后端微服务返回的结果并保存,让后面的Filter写回给客户端。
