本文章简要对SpringCloudGateway的源码进行分析。
目的让读者能大致了解到Gateway的执行流程,
前序
源码阅读前的建议:
1.了解过Spring&SpringBoot源码(非必需)。
2.了解过Reactor框架的基础(非必需)。
简介
网关的作用在这里就不赘述了,下面这个图(官网上的)描述了网关的大致执行流程原理,现在看着肯定很抽象,本文阅读完后再看这张图你绝对会很清晰。
看图可知道几个重要的部分:
- Gateway Handler Mapping
- Gateway Web Handler
- Filter
使用Gateway时需要加入的依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
一段简单的路由配置信息:
- id: web-consumer
uri: lb://web-consumer
predicates: // 谓词
- Path=/consumer/**
- Method=GET,POST
filters: // 过滤器
- StripPrefix=1
同样的套路,与Spring Boot整合肯定会有个 xxxAutoConfiguration的自动配置类:
GatewayAutoConfiguration:网关的自动配置类。
GatewayProperties:网关的参数配置类。
但是仅凭上面的配置类我们是不好源码切入请求的执行的流程,所以我们需要关注Web Flux,一个和spring Mvc作用差不多的框架,Web Flux是用Reactor框架编写并且基于Netty实现的响应式编程,spring Mvc是命令式编程。
Web Flux和Spring Mvc很像也有着几大组件:
- DispatcherHandler
- HandlerMapping
- HandlerAdapter
- Handler
了解过Spring Mvc的源码,就会感觉上面的东西会很熟悉,没错,都差不多。
这下源码切入点就找到了 DispatcherHandler。
DispatcherHandler:核心处理请求方法
public class DispatcherHandler implements WebHandler, ApplicationContextAware {
// 注入进来的 HandlerMapping HandlerAdapter
@Nullable
private List<HandlerMapping> handlerMappings;
@Nullable
private List<HandlerAdapter> handlerAdapters;
@Nullable
private List<HandlerResultHandler> resultHandlers;
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
if (this.handlerMappings == null) {
return createNotFoundError();
}
return Flux.fromIterable(this.handlerMappings)
// 根据 HandlerMapping 获取 Handler
.concatMap(mapping -> mapping.getHandler(exchange))
.next()
.switchIfEmpty(createNotFoundError())
// 执行找到的 Handler
.flatMap(handler -> invokeHandler(exchange, handler))
// 结果处理 返回
.flatMap(result -> handleResult(exchange, result));
}
下面我们来仔细分析这几步过程。
1.mapping.getHandler(exchange)
这个方法会返回一个 Handler
@Override
public Mono<Object> getHandler(ServerWebExchange exchange) {
// getHandlerInternal() 这个方法有多个实现
// 网关实现的mapping类是 RoutePredicateHandlerMapping
return getHandlerInternal(exchange).map(handler -> {
ServerHttpRequest request = exchange.getRequest();
// ...
return handler;
});
}
// RoutePredicateHandlerMapping#getHandlerInternal
public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
private final FilteringWebHandler webHandler;
@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());
// lookupRoute方法 是查找 Route,Route就是我们在配置文件里面配置的一个个的服务路由信息
// 这个方法会找到匹配当前请求的 Route
return lookupRoute(exchange)
.flatMap((Function<Route, Mono<?>>) r -> {
exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
// webHandler 是 FilteringWebHandler
return Mono.just(webHandler);
}).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
})));
}
}
protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
// routeLocator 是路由加载器,会读取配置文件中的服务路由信息。
return this.routeLocator.getRoutes()
.concatMap(route -> Mono.just(route).filterWhen(r -> {
exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
// 核心是这一句 r.getPredicate().apply(exchange)
// 逐个执行这个这个路由下面配置的谓词列表
return r.getPredicate().apply(exchange);
})
.onErrorResume(e -> Mono.empty()))
.next()
.map(route -> {
validateRoute(route, exchange);
return route;
});
}
HandlerMapping: RoutePredicateHandlerMapping是GateWay实现的类,从类名字都可以看出这个是用来处理路由上面的谓词的。
RouteLocator:是加载配置中的路由配置,关于配置加载的分析下一篇在进行分析。
上面这部分可以看出:
请求到来 —》匹配路由—〉执行路由谓词 —》返回 Handler
路由谓词就类似断言一样执行失败后整个请求就结束了,后续配置的filter都不会被执行,从这也可以看出:
predicates 优先于filters。
2.invokeHandler(exchange, handler)
private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
if (this.handlerAdapters != null) {
for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
// 找到符合 handler 的 handlerAdapter
if (handlerAdapter.supports(handler)) {
// 执行 handler
return handlerAdapter.handle(exchange, handler);
}
}
}
return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
}
上面可以看出我们返回的handler是FilteringWebHandler。
而他对应的适配器是:SimpleHandlerAdapter。
public class SimpleHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return WebHandler.class.isAssignableFrom(handler.getClass());
}
@Override
public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
WebHandler webHandler = (WebHandler) handler;
// 执行 handler 的 webHandler.handle()方法。
Mono<Void> mono = webHandler.handle(exchange);
return mono.then(Mono.empty());
}
}
所以我们重点关注一下FilteringWebHandler的handle()方法即可。
FilteringWebHandler 的注入是在 GatewayAutoConfiguration 中的。
@Bean
public FilteringWebHandler filteringWebHandler(List<GlobalFilter> globalFilters) {
// 加载了我们自定义的 GlobalFilter
return new FilteringWebHandler(globalFilters);
}
public class FilteringWebHandler implements WebHandler {
private final List<GatewayFilter> globalFilters;
public FilteringWebHandler(List<GlobalFilter> globalFilters) {
// 会把 GlobalFilter 统一包装成 GatewayFilter
this.globalFilters = loadFilters(globalFilters);
}
private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
return filters.stream().map(filter -> {
GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter);
// 排序
if (filter instanceof Ordered) {
int order = ((Ordered) filter).getOrder();
return new OrderedGatewayFilter(gatewayFilter, order);
}
return gatewayFilter;
}).collect(Collectors.toList());
}
/**
* 过滤链的核心处理方法
**/
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
// 获取 匹配当前请求的 Route
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
// 配置中当前路由中指定的 Filters
List<GatewayFilter> gatewayFilters = route.getFilters();
// 内置的filter + 指定的 filter
List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
combined.addAll(gatewayFilters);
AnnotationAwareOrderComparator.sort(combined);
// 执行 filters 链
return new DefaultGatewayFilterChain(combined).filter(exchange);
}
}
这次请求需要执行的过滤链:
DefaultGatewayFilterChain这个类的功能就是组织了整条链的执行。
private static class DefaultGatewayFilterChain implements GatewayFilterChain {
private final int index;
private final List<GatewayFilter> filters;
DefaultGatewayFilterChain(List<GatewayFilter> filters) {
this.filters = filters;
this.index = 0;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange) {
return Mono.defer(() -> {
if (this.index < filters.size()) {
GatewayFilter filter = filters.get(this.index);
// 执行下一条链
DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this,this.index + 1);
// 执行链
return filter.filter(exchange, chain);
}
else {
return Mono.empty(); // complete
}
});
}
}
以上就是大致的请求执行流程,其中有几个内置链是我们需要了解一下的执行过程的:
1.LoadBalancerClientFilter
该Filter功能就是:利用Ribbon的负载均衡选出一个Server。
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
String schemePrefix = exchange.getAttribute(GATEWAY_SCHEME_PREFIX_ATTR);
if (url == null
|| (!"lb".equals(url.getScheme()) && !"lb".equals(schemePrefix))) {
return chain.filter(exchange);
}
// preserve the original url
addOriginalRequestUrl(exchange, url);
// 核心:负载均衡 执行内置的 Rule(默认是轮训Rule) 选出一个Server
// ServiceInstance 中有下游服务的IP,端口等等信息
// 思考:服务的实例是从注册中心拉取的,何时拉取的呢? 更新策略是什么呢?
final ServiceInstance instance = choose(exchange);
URI uri = exchange.getRequest().getURI();
String overrideScheme = instance.isSecure() ? "https" : "http";
if (schemePrefix != null) {
overrideScheme = url.getScheme();
}
// 这句也是比较核心:完成了URL替换
// 我们访问是直接访问的网关,这个地方会替换 URL 替换成下游的访问地址
// http://127.0.0.1:8888/web/index --》http://127.0.0.1:8901/web/index
URI requestUrl = loadBalancer.reconstructURI(
new DelegatingServiceInstance(instance, overrideScheme), uri);
// GATEWAY_REQUEST_URL_ATTR 真实要访问的 接口地址
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
return chain.filter(exchange);
}
2.NettyRoutingFilter
该Filter功能就是:请求下游服务接口返回。
@Override
@SuppressWarnings("Duplicates")
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 获取上面替换了的下游服务真实的接口地址
URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);
ServerHttpRequest request = exchange.getRequest();
final HttpMethod method = HttpMethod.valueOf(request.getMethodValue());
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
// 核心:请求转发给下游
Flux<HttpClientResponse> responseFlux = getHttpClient(route, exchange)
.headers(headers -> {
headers.add(httpHeaders);
headers.remove(HttpHeaders.HOST);
// send 把组装的数据用 http 形式请求下游服务的接口
}).request(method).uri(url).send((req, nettyOutbound) -> {
return nettyOutbound.send(request.getBody().map(this::getByteBuf));
}).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()));
// res 是请求接口返回的数据
setResponseStatus(res, response);
HttpHeaders filteredResponseHeaders = HttpHeadersFilter.filter(
getHeadersFilters(), headers, exchange, Type.RESPONSE);
exchange.getAttributes().put(CLIENT_RESPONSE_HEADER_NAMES,
filteredResponseHeaders.keySet());
response.getHeaders().putAll(filteredResponseHeaders);
// 返回结果
return Mono.just(res);
});
return responseFlux.then(chain.filter(exchange));
}
其他链的执行过程,感兴趣的可以自行了解。
来幅图大致总结一下流程:
总体来看还是比较简单的,没有特别复杂的流程,了解了这个大致流程,如果要扩展网关的功能,大致知道切入点在哪里,然后再做进一步的深究。