Spring-Cloud-Gateway-流程细节(四)

1. 思考题

  • 如何从 DispatcherHandler 匹配对应的 HandlerMapping?如何从 HandlerMapping 匹配 Route?
  • FilteringWebHandler 创建 GatewayFilterChain 处理请求?如何从 HandlerMapping 匹配 Route?
  • 如何调用到 FilteringWebHandler 的 handler 方法?
  • FilteringWebHandler 创建 GatewayFilterChain 处理请求?

    2. 简单流程

书接上回:

2.1. DispatcherHandler#handle

@Override
    public Mono<Void> handle(ServerWebExchange exchange) {
       // 对于 handlerMapping 判空 
        if (this.handlerMappings == null) {
            return createNotFoundError();
        }
        return Flux.fromIterable(this.handlerMappings)
                .concatMap(mapping -> mapping.getHandler(exchange))
                .next()
                .switchIfEmpty(createNotFoundError())
                .flatMap(handler -> invokeHandler(exchange, handler))
                .flatMap(result -> handleResult(exchange, result));
    }

2.2. handlerMappings 详情

此时 handlerMappings 里面有什么内容以及分别有什么作用!

其中包括了

  • WebFluxEndpointHandlerMapping:使用 Spring WebFlux 使 Web 终结点在 HTTP 上可用的自定义处理程序映射。
  • ControllerEndpointHandlerMapping:匹配 @ControllerEndpoint 和 @RestControllerEndpoint
  • RouterFunctionMapping:匹配WebFlux的router functions;
  • RequestMappingHandlerMapping:匹配 @RequestMapping 标注;
  • RoutePredicateHandlerMapping:匹配Gateway中路由断言的集合;
  • SimpleUrlHandlerMapping:匹配静态资源;

注意concatMap(mapping -> mapping.getHandler(exchange))对于这个语句的理解,是对应的 6 个 handlerMapping 都执行一遍自己的getHandlerInternal方法。

2.3. AbstractHandlerMapping#getHandler 方法

@Override
public Mono<Object> getHandler(ServerWebExchange exchange) {
   return getHandlerInternal(exchange).map(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 (!this.corsProcessor.process(config, exchange) || CorsUtils.isPreFlightRequest(request)) {
            return REQUEST_HANDLED_HANDLER;
         }
      }
      return handler;
   });
}

其中对于 RoutePredicateHandlerMapping 来说,在执行getHandlerInternal(exchange)这一步的时候,调用实际自己的实现,然后最终把RoutePredicateHandlerMapping返回的 handler 处理之后继续往上返回。

2.4. RoutePredicateHandlerMapping#getHandlerInternal

@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
   logger.info(" -> RoutePredicateHandlerMapping#getHandlerInternal");
   // don't handle requests on management port if set and different than server port
   if (this.managementPortType == DIFFERENT && this.managementPort != null
         && exchange.getRequest().getURI().getPort() == this.managementPort) {
      return Mono.empty();
   }
   logger.info("设置当前处理使用的 GATEWAY_HANDLER_MAPPER_ATTR 是 RoutePredicateHandlerMapping "
         + "-> RoutePredicateHandlerMapping#getHandlerInternal");
   exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());
   Mono<Route> routeMono = lookupRoute(exchange);
   logger.info("当前匹配的 Route 是:" + routeMono + " -> RoutePredicateHandlerMapping#getHandlerInternal");
   return routeMono
         .log("route-predicate-handler-mapping", Level.FINER) //name this
         .flatMap((Function<Route, Mono<?>>) r -> {
            logger.info("移除当前缓存的 GATEWAY_PREDICATE_ROUTE_ATTR : " + exchange.getAttributes()
                  .get(GATEWAY_PREDICATE_ROUTE_ATTR) + " -> RoutePredicateHandlerMapping#getHandlerInternal");
            exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
            if (logger.isDebugEnabled()) {
               logger.debug(
                     "Mapping [" + getExchangeDesc(exchange) + "] to " + r);
            }
            logger.info("设置当前正在使用的 GATEWAY_ROUTE_ATTR 为:" + r +
                  " -> RoutePredicateHandlerMapping#getHandlerInternal");
            exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
                        // 在此处返回了对应的 webHandler,此处特指的是 FilteringWebHandler.
            return Mono.just(webHandler);
         }).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
            logger.info("未找到合适的 Route,清理历史 Route 上下文,返回空 -> "
                  + "RoutePredicateHandlerMapping#getHandlerInternal");
            exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
            if (logger.isTraceEnabled()) {
               logger.trace("No RouteDefinition found for ["
                     + getExchangeDesc(exchange) + "]");
            }
         })));
}

此处根据谓词规则匹配对应的 Route,然后exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);把对应的 Route 加载到上下文中,之后返回 FilteringWebHandler。

2.5. DispatcherHandler#invokeHandler 执行细节

private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
   if (this.handlerAdapters != null) {
      for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
         if (handlerAdapter.supports(handler)) {
            return handlerAdapter.handle(exchange, handler);
         }
      }
   }
   return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
}

走到这一步,我们逻辑实现,显示判断是否有对应的 handlerAdapter 处理器,然后对应的 handlerAdapter 是否支持处理 FilteringWebHandler。执行断点我们观察如下,this.handlerAdapter包含:

  • RequestMappingHandlerAdapter:支持处理 @RequestMapping 方法
  • HandlerFunctionAdapter:支持处理 HandlerFuncitons
  • SimpleHandlerAdapter:处理普通 Web 处理程序与通用调度器处理程序

    2.6. 不同 HandlerAdapter 的 support 方法

RequestMappingHandlerAdapter,是否属于 HandlerMethod

@Override
public boolean supports(Object handler) {
   return handler instanceof HandlerMethod;
}

HandlerFunctionAdapter,是否属于 HandlerFunction

@Override
public boolean supports(Object handler) {
   return handler instanceof HandlerFunction;
}

SimpleHandlerAdapter,是否属于 WebHandler

@Override
public boolean supports(Object handler) {
   return WebHandler.class.isAssignableFrom(handler.getClass());
}

根据上述代码,我们已经很清楚了返回的 FilteringWebHandler 当然属于 WebHandler,所以会调用 SimpleHandlerAdapter 的 handle 方法。

2.7. SimpleHandlerAdapter#handle

public class SimpleHandlerAdapter implements HandlerAdapter {
 ...
   @Override
   public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
      WebHandler webHandler = (WebHandler) handler;
      Mono<Void> mono = webHandler.handle(exchange); //①
      return mono.then(Mono.empty());
   }
}

周周转转,发现又回到了webHandler.handle(exchange)方法,也就是我们FilteringWebHandlerhandle方法。

2.8. FilteringWebHandler#handle

@Override
public Mono<Void> handle(ServerWebExchange exchange) {
   logger.info("DispatcherHandler#invokeHandler -> handlerAdapter.handle(exchange, handler); \\n "
         + "执行到 FilteringWebHandler -> FilteringWebHandler#handle");
   Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
   List<GatewayFilter> gatewayFilters = route.getFilters();
   List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
   combined.addAll(gatewayFilters);
   logger.info("对 Filter 进行排序 -> FilteringWebHandler#handle");
   AnnotationAwareOrderComparator.sort(combined);
   if (logger.isDebugEnabled()) {
      logger.debug("Sorted gatewayFilterFactories: " + combined);
   }
   logger.info("创建默认的 DefaultGatewayFilterChain -> FilteringWebHandler#handle");
   return new DefaultGatewayFilterChain(combined).filter(exchange);
}

通过程序我们可以看到,

  • 首先获取在DispatcherHandlergetHandlerInternal中设置到上下文的 Route;
  • 其次获取Route下面所有的filter,把当前RoutefilterGlobal filter合并;
  • 然后对所有的filter进行排序;
  • 最后创建DefaultGatewayFilterChain,使用责任链模式,链式调用。
  1. Reactor 基础知识

https://mubu.com/doc/1qwRixFnbHv图片


文章作者: HoldDie
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 HoldDie !
评论
 上一篇
Spring-Cloud-Gateway-全局filter细品(五) Spring-Cloud-Gateway-全局filter细品(五)
目标 温故 Java8 常见函数式用法 再过一下 lookupRoute 方法 过一遍 9 默认全局 Filter Java 8 常见函数式用法Consumer 表达式一个消费型的接口,通过传入参数,然后输出值,无返回值。接连两个cons
2021-01-11
下一篇 
Spring-Cloud-Gateway-核心流程(三) Spring-Cloud-Gateway-核心流程(三)
抓主线 启动如何注入 DispatcherHandler ?0. ReactorHttpHandlerAdapter此处长话短说,在 Spring Webflux 启动的过程调用链如下: <init>:50, ReactorHttpH
2021-01-11
  目录