本系列代码地址:https://github.com/JoJoTec/sp...

咱们持续剖析上一节提到的 WebHandler。退出 Spring Cloud Sleuth 以及 Prometheus 相干依赖之后, Spring Cloud Gateway 的解决流程如下所示:

Spring Cloud Gateway 入口 -> WebFlux 的 DefaultWebFilterChain

Spring Cloud Gateway 是基于 Spring WebFlux 开发的异步响应式网关,异步响应式代码比拟难以了解和浏览,我这里给大家分享一种办法去了解,通过这个流程来了解 Spring Cloud Gateway 的工作流程以及底层原理。其实能够了解为,上图这个流程,就是拼出来一个残缺的 Mono(或者 Flux)流,最初 subscribe 执行。

当收到一个申请的时候,会通过 org.springframework.web.server.handler.DefaultWebFilterChain,这是 WebFilter 的调用链,这个链路包含三个 WebFilter:

  • org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter:增加 Prometheus 相干依赖之后,会有这个 MetricsWebFilter,用于记录申请解决耗时,采集相干指标。
  • org.springframework.cloud.sleuth.instrument.web.TraceWebFilter:增加 Spring Cloud Sleuth 相干依赖之后,会有这个 TraceWebFilter。
  • org.springframework.cloud.gateway.handler.predicate.WeightCalculatorWebFilter:Spring Cloud Gateway 路由权重相干配置性能相干实现类,这个咱们这里不关怀。

在这个 DefaultWebFilterChain 会造成这样一个 Mono,咱们顺次将他们标记进去,首先是入口代码 org.springframework.web.server.handler.DefaultWebFilterChain#filter

public Mono<Void> filter(ServerWebExchange exchange) {    return Mono.defer(() ->            // this.currentFilter != null 代表 WebFilter 链还没有完结            // this.chain != null 代表 WebFilter 链不为空            this.currentFilter != null && this.chain != null ?                    //在 WebFilter 链没有完结的状况下,调用 WebFilter                    invokeFilter(this.currentFilter, this.chain, exchange) :                    //在 WebFilter 完结的状况下,调用 handler                     this.handler.handle(exchange));}

对于咱们这里的 WebFilter 链的第一个 MetricsWebFilter,假如启用了对应的采集统计的话,这时候生成的 Mono 就是:

return Mono.defer(() ->    chain.filter(exchange).transformDeferred((call) -> {        long start = System.nanoTime();        return call                //胜利时,记录响应工夫                .doOnSuccess((done) -> MetricsWebFilter.this.onSuccess(exchange, start))                //失败时,记录响应工夫和异样                .doOnError((cause) -> MetricsWebFilter.this.onError(exchange, start, cause));    }););

这里为了不便,咱们对代码做了简化,因为咱们要将整个链路的所有 Mono 和 Flux 拼接在一起行程残缺链路,所以本来是 MetricsWebFilter中的 onSuccess(exchange, start)办法,被改成了 MetricsWebFilter.this.onSuccess(exchange, start) 这种伪代码。

接着,依据DefaultWebFilterChain 的源码剖析,chain.filter(exchange) 会持续 WebFilter 链路,达到下一个 WebFilter,即 TraceWebFilter。通过 TraceWebFilter,Mono 就会变成:

return Mono.defer(() ->    new MonoWebFilterTrace(source, chain.filter(exchange), TraceWebFilter.this.isTracePresent(), TraceWebFilter.this, TraceWebFilter.this.spanFromContextRetriever()).transformDeferred((call) -> {        //MetricsWebFilter 相干的解决,在后面的代码中给出了,这里省略    }););

能够看出,在 TraceWebFilter 中,整个外部 Mono (chain.filter(exchange) 后续的后果)都被封装成了一个 MonoWebFilterTrace,这也是放弃链路追踪信息的要害实现。

持续 WebFilter 链路,通过最初一个 WebFilter WeightCalculatorWebFilter; 这个 WebFilter 咱们不关怀,外面对路由权重做了一些计算操作,咱们这里间接疏忽即可。这样咱们就走完了所有 WebFilter 链路,来到了最初的调用 DefaultWebFilterChain.this.handler,这个 handler 就是 org.springframework.web.reactive.DispatcherHandler。在 DispatcherHandler 中,咱们会计算前途由并发送申请到符合条件的 GatewayFilter。通过 DispatcherHandler,Mono 会变成:

return Mono.defer(() ->    new MonoWebFilterTrace(source,         Flux.fromIterable(DispatcherHandler.this.handlerMappings) //读取所有的 handlerMappings            .concatMap(mapping -> mapping.getHandler(exchange)) //按顺序调用所有的 handlerMappings 的 getHandler 办法,如果有对应的 Handler 会返回,否则返回 Mono.empty();            .next() //找到第一个返回不是 Mono.empty() 的 Handler            .switchIfEmpty(DispatcherHandler.this.createNotFoundError()) //如果没有返回不为 Mono.empty() 的 handlerMapping,则间接返回 404            .flatMap(handler -> DispatcherHandler.this.invokeHandler(exchange, handler)) //调用对应的 Handler            .flatMap(result -> DispatcherHandler.this.handleResult(exchange, result)), //处理结果    TraceWebFilter.this.isTracePresent(), TraceWebFilter.this, TraceWebFilter.this.spanFromContextRetriever()).transformDeferred((call) -> {        //MetricsWebFilter 相干的解决,在后面的代码中给出了,这里省略    }););

handlerMappings 包含:

  • org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndPointHandlerMapping:因为咱们我的项目中增加了 Actuator 相干依赖,所以这里有这个 HandlerMapping。Actuator 相干门路映射,不是咱们这里关怀的。然而能够看出,Actuator 相干门路优先于 Spring Cloud Gateway 配置路由
  • org.springframework.boot.actuate.endpoint.web.reactive.ControllerEndpointHandlerMapping:因为咱们我的项目中增加了 Actuator 相干依赖,所以这里有这个 HandlerMapping。应用 @ControllerEndpoint 或者 @RestControllerEndpoint 注解标注的 Actuator 相干门路映射,不是咱们这里关怀的。
  • org.springframework.web.reactive.function.server.support.RouterFunctionMapping:在 Spring-WebFlux 中,你能够定义很多不同的 RouterFunction 来管制门路路由,但这也不是咱们这里关怀的。然而能够看出,自定义的 RouterFunction 会优先于 Spring Cloud Gateway 配置路由
  • org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping:针对 @RequestMapping 注解的门路的 HandlerMapping,不是咱们这里关怀的。然而能够看出,如果你在 Spring Cloud Gateway 中指定 RequestMapping 门路,会优先于 Spring Cloud Gateway 配置路由
  • org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping:这个是 Spring Cloud Gateway 的 HandlerMapping,会读取 Spring Cloud Gateway 配置并生成路由。这个是咱们这里要详细分析的。

其实这些 handlerMappings,咱们这里必定走的是 RoutePredicateHandlerMapping 的相干逻辑,所以咱们的 Mono 又能够简化成:

 return Mono.defer(() ->    new MonoWebFilterTrace(source,         RoutePredicateHandlerMapping.this.getHandler(exchange)            .switchIfEmpty(DispatcherHandler.this.createNotFoundError()) //如果没有返回不为 Mono.empty() 的 handlerMapping,则间接返回 404            .flatMap(handler -> DispatcherHandler.this.invokeHandler(exchange, handler)) //调用对应的 Handler            .flatMap(result -> DispatcherHandler.this.handleResult(exchange, result)), //处理结果    TraceWebFilter.this.isTracePresent(), TraceWebFilter.this, TraceWebFilter.this.spanFromContextRetriever()).transformDeferred((call) -> {        //MetricsWebFilter 相干的解决,在后面的代码中给出了,这里省略    }););

咱们来看 RoutePredicateHandlerMapping,首先这些 handlerMapping 都是继承了抽象类 org.springframework.web.reactive.handler.AbstractHandlerMapping, 后面咱们拼接的 Mono 外面的 getHandler 的实现其实就在这个抽象类中:

 public Mono<Object> getHandler(ServerWebExchange exchange) {    //调用形象办法 getHandlerInternal 获取真正的 Handler    return getHandlerInternal(exchange).map(handler -> {        //这里针对 handler 做一些日志记录        if (logger.isDebugEnabled()) {            logger.debug(exchange.getLogPrefix() + "Mapped to " + handler);        }        // 跨域解决        ServerHttpRequest request = exchange.getRequest();        if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {            CorsConfiguration config = (this.corsConfigurationSource != null ?                    this.corsConfigurationSource.getCorsConfiguration(exchange) : null);            CorsConfiguration handlerConfig = getCorsConfiguration(handler, exchange);            config = (config != null ? config.combine(handlerConfig) : handlerConfig);            if (config != null) {                config.validateAllowCredentials();            }            if (!this.corsProcessor.process(config, exchange) || CorsUtils.isPreFlightRequest(request)) {                return NO_OP_HANDLER;            }        }        return handler;    });}

能够看出,其实外围就是每个实现类的 getHandlerInternal(exchange) 办法,所以在咱们拼接的 Mono 中,咱们会疏忽抽象类中的针对 handler 之后的 map 解决。

return Mono.defer(() ->    new MonoWebFilterTrace(source,         RoutePredicateHandlerMapping.this.getHandlerInternal(exchange)            .switchIfEmpty(DispatcherHandler.this.createNotFoundError()) //如果没有返回不为 Mono.empty() 的 handlerMapping,则间接返回 404            .flatMap(handler -> DispatcherHandler.this.invokeHandler(exchange, handler)) //调用对应的 Handler            .flatMap(result -> DispatcherHandler.this.handleResult(exchange, result)), //处理结果    TraceWebFilter.this.isTracePresent(), TraceWebFilter.this, TraceWebFilter.this.spanFromContextRetriever()).transformDeferred((call) -> {        //MetricsWebFilter 相干的解决,在后面的代码中给出了,这里省略    }););

接下来通过 RoutePredicateHandlerMappinggetHandlerInternal(exchange) 办法,咱们的 Mono 变成了:

return Mono.defer(() ->    new MonoWebFilterTrace(source,         RoutePredicateHandlerMapping.this.lookupRoute(exchange) //依据申请寻找路由                .flatMap((Function<Route, Mono<?>>) r -> {                    exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r); //将路由放入 Attributes 中,前面咱们还会用到                    return Mono.just(RoutePredicateHandlerMapping.this.webHandler); //返回 RoutePredicateHandlerMapping 的 FilteringWebHandler                }).switchIfEmpty( //如果为 Mono.empty(),也就是没找到路由                    Mono.empty() //返回 Mono.empty()                    .then(Mono.fromRunnable(() -> { //返回 Mono.empty() 之后,记录日志                        if (logger.isTraceEnabled()) {                            logger.trace("No RouteDefinition found for [" + getExchangeDesc(exchange) + "]");                    }                })))            .switchIfEmpty(DispatcherHandler.this.createNotFoundError()) //如果没有返回不为 Mono.empty() 的 handlerMapping,则间接返回 404            .flatMap(handler -> DispatcherHandler.this.invokeHandler(exchange, handler)) //调用对应的 Handler            .flatMap(result -> DispatcherHandler.this.handleResult(exchange, result)), //处理结果    TraceWebFilter.this.isTracePresent(), TraceWebFilter.this, TraceWebFilter.this.spanFromContextRetriever()).transformDeferred((call) -> {        //MetricsWebFilter 相干的解决,在后面的代码中给出了,这里省略    }););

RoutePredicateHandlerMapping.this.lookupRoute(exchange) 依据申请寻找路由,这个咱们就不具体开展了,其实就是依据你的 Spring Cloud Gateway 配置,找到适合的路由。接下来咱们来看调用对应的 Handler,即 FilteringWebHandler。DispatcherHandler.this.invokeHandler(exchange, handler) 咱们这里也不具体开展,咱们晓得其实就是调用 Handler 的 handle 办法,即 FilteringWebHandler 的 handle 办法,所以 咱们的 Mono 变成了:

return Mono.defer(() ->    new MonoWebFilterTrace(source,         RoutePredicateHandlerMapping.this.lookupRoute(exchange) //依据申请寻找路由                .flatMap((Function<Route, Mono<?>>) r -> {                    exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r); //将路由放入 Attributes 中,前面咱们还会用到                    return Mono.just(RoutePredicateHandlerMapping.this.webHandler); //返回 RoutePredicateHandlerMapping 的 FilteringWebHandler                }).switchIfEmpty( //如果为 Mono.empty(),也就是没找到路由                    Mono.empty()                     .then(Mono.fromRunnable(() -> { //返回 Mono.empty() 之后,记录日志                        if (logger.isTraceEnabled()) {                            logger.trace("No RouteDefinition found for [" + getExchangeDesc(exchange) + "]");                    }                })))            .switchIfEmpty(DispatcherHandler.this.createNotFoundError()) //如果没有返回不为 Mono.empty() 的 handlerMapping,则间接返回 404            .then(FilteringWebHandler.this.handle(exchange).then(Mono.empty())) //调用对应的 Handler            .flatMap(result -> DispatcherHandler.this.handleResult(exchange, result)), //处理结果    TraceWebFilter.this.isTracePresent(), TraceWebFilter.this, TraceWebFilter.this.spanFromContextRetriever()).transformDeferred((call) -> {        //MetricsWebFilter 相干的解决,在后面的代码中给出了,这里省略    }););

因为调用对应的 Handler,最初返回的是 Mono.empty(),所以前面的 flatMap 其实不会执行了。所以咱们能够将最初的处理结果这一步去掉。所以咱们的 Mono 就变成了:

return Mono.defer(() ->    new MonoWebFilterTrace(source,         RoutePredicateHandlerMapping.this.lookupRoute(exchange) //依据申请寻找路由                .flatMap((Function<Route, Mono<?>>) r -> {                    exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r); //将路由放入 Attributes 中,前面咱们还会用到                    return Mono.just(RoutePredicateHandlerMapping.this.webHandler); //返回 RoutePredicateHandlerMapping 的 FilteringWebHandler                }).switchIfEmpty( //如果为 Mono.empty(),也就是没找到路由                    Mono.empty()                     .then(Mono.fromRunnable(() -> { //返回 Mono.empty() 之后,记录日志                        if (logger.isTraceEnabled()) {                            logger.trace("No RouteDefinition found for [" + getExchangeDesc(exchange) + "]");                    }                })))            .switchIfEmpty(DispatcherHandler.this.createNotFoundError()) //如果没有返回不为 Mono.empty() 的 handlerMapping,则间接返回 404            .then(FilteringWebHandler.this.handle(exchange).then(Mono.empty()))), //调用对应的 Handler    TraceWebFilter.this.isTracePresent(), TraceWebFilter.this, TraceWebFilter.this.spanFromContextRetriever()).transformDeferred((call) -> {        //MetricsWebFilter 相干的解决,在后面的代码中给出了,这里省略    }););

FilteringWebHandler.this.handle(exchange) 其实就是从 Attributes 中取出路由,从路由中取出对应的 GatewayFilters,与全局 GatewayFilters 放到同一个 List 中,并依照这些 GatewayFilter 的程序排序(能够通过实现 org.springframework.core.Ordered 接口来制订程序),而后生成 DefaultGatewayFilterChain 即 GatewayFilter 链路。对应的源码是:

public Mono<Void> handle(ServerWebExchange exchange) {    //从 Attributes 中取出路由,从路由中取出对应的 GatewayFilters    Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);    List<GatewayFilter> gatewayFilters = route.getFilters();    //与全局 GatewayFilters 放到同一个 List 中    List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);    combined.addAll(gatewayFilters);    //依照这些 GatewayFilter 的程序排序(能够通过实现 `org.springframework.core.Ordered` 接口来制订程序)    AnnotationAwareOrderComparator.sort(combined);        if (logger.isDebugEnabled()) {        logger.debug("Sorted gatewayFilterFactories: " + combined);    }    //生成调用链    return new DefaultGatewayFilterChain(combined).filter(exchange);}

这个 GatewayFilter 调用链和 WebFilter 调用链相似,参考 DefaultGatewayFilterChain 的源码:

public Mono<Void> filter(ServerWebExchange exchange) {    return Mono.defer(() -> {        //如果链路没有完结,则持续链路        if (this.index < filters.size()) {            GatewayFilter filter = filters.get(this.index);            //这里将 index + 1,也就是调用链路中的下一个 GatewayFilter            DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this, this.index + 1);            //每个 filter 中如果想要持续链路,则会调用 chain.filter(exchange),这也是咱们开发 GatewayFilter 的时候的应用形式            return filter.filter(exchange, chain);        }        else {            //达到开端,链路完结            return Mono.empty(); // complete        }    });}

所以,通过 DefaultGatewayFilterChain 后,咱们的 Mono 就会变成:

return Mono.defer(() ->    new MonoWebFilterTrace(source,         RoutePredicateHandlerMapping.this.lookupRoute(exchange) //依据申请寻找路由                .flatMap((Function<Route, Mono<?>>) r -> {                    exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r); //将路由放入 Attributes 中,前面咱们还会用到                    return Mono.just(RoutePredicateHandlerMapping.this.webHandler); //返回 RoutePredicateHandlerMapping 的 FilteringWebHandler                }).switchIfEmpty( //如果为 Mono.empty(),也就是没找到路由                    Mono.empty()                     .then(Mono.fromRunnable(() -> { //返回 Mono.empty() 之后,记录日志                        if (logger.isTraceEnabled()) {                            logger.trace("No RouteDefinition found for [" + getExchangeDesc(exchange) + "]");                    }                })))            .switchIfEmpty(DispatcherHandler.this.createNotFoundError()) //如果没有返回不为 Mono.empty() 的 handlerMapping,则间接返回 404            .then(new DefaultGatewayFilterChain(combined).filter(exchange).then(Mono.empty()))), //调用对应的 Handler    TraceWebFilter.this.isTracePresent(), TraceWebFilter.this, TraceWebFilter.this.spanFromContextRetriever()).transformDeferred((call) -> {        //MetricsWebFilter 相干的解决,在后面的代码中给出了,这里省略    }););

再持续开展 DefaultGatewayFilterChain 的链路调用,能够失去:

return Mono.defer(() ->    new MonoWebFilterTrace(source,         RoutePredicateHandlerMapping.this.lookupRoute(exchange) //依据申请寻找路由                .flatMap((Function<Route, Mono<?>>) r -> {                    exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r); //将路由放入 Attributes 中,前面咱们还会用到                    return Mono.just(RoutePredicateHandlerMapping.this.webHandler); //返回 RoutePredicateHandlerMapping 的 FilteringWebHandler                }).switchIfEmpty( //如果为 Mono.empty(),也就是没找到路由                    Mono.empty()                     .then(Mono.fromRunnable(() -> { //返回 Mono.empty() 之后,记录日志                        if (logger.isTraceEnabled()) {                            logger.trace("No RouteDefinition found for [" + getExchangeDesc(exchange) + "]");                    }                })))            .switchIfEmpty(DispatcherHandler.this.createNotFoundError()) //如果没有返回不为 Mono.empty() 的 handlerMapping,则间接返回 404            .then(                Mono.defer(() -> {                    //如果链路没有完结,则持续链路                    if (DefaultGatewayFilterChain.this.index < DefaultGatewayFilterChain.this.filters.size()) {                        GatewayFilter filter = DefaultGatewayFilterChain.this.filters.get(DefaultGatewayFilterChain.this.index);                        //这里将 index + 1,也就是调用链路中的下一个 GatewayFilter                        DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(DefaultGatewayFilterChain.this, DefaultGatewayFilterChain.this.index + 1);                        //每个 filter 中如果想要持续链路,则会调用 chain.filter(exchange),这也是咱们开发 GatewayFilter 的时候的应用形式                        return filter.filter(exchange, chain);                    }                    else {                        return Mono.empty(); //链路实现                    }                })                .then(Mono.empty()))            ), //调用对应的 Handler    TraceWebFilter.this.isTracePresent(), TraceWebFilter.this, TraceWebFilter.this.spanFromContextRetriever()).transformDeferred((call) -> {        //MetricsWebFilter 相干的解决,在后面的代码中给出了,这里省略    }););

这样,就造成了 Spring Cloud Gateway 针对路由申请的残缺 Mono 调用链。

微信搜寻“我的编程喵”关注公众号,每日一刷,轻松晋升技术,斩获各种offer