1. 程式人生 > 實用技巧 >Spring-Cloud-Gateway-流程細節(四)

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,使用責任鏈模式,鏈式呼叫。
  • Reactor 基礎知識

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