1.概览

      本节是gateway入口DispatcherHandler.handle()方法原理分享的第二节,本节主要分享handle方法内部逻辑中的mapping.getHandler(exchange)方法的实现原理,本节较长,希望大家耐心看完。

2. handle方法回顾

      为了方便分享,我还是把handle方法的源码展示如下:

@Override
public Mono<Void> handle(ServerWebExchange exchange) {
   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));
}

      上一节我分享了handlerMappings是如何获取的,本节分享mapping.getHandler(exchange)方法的实现细节,探索下handler是如何获取的。

3. HandlerMappings继承关系

      为了便于理解,我准备了一张HandlerMapping接口的类继承图,6个handlerMappings bean被标记成了绿色(如果对这6个bean的来源有疑问,请参考上一节)。
在这里插入图片描述

4. getHandlerInternal

      Flux.fromIterable(this.handlerMappings)会迭代handlerMappings list,迭代出的每个mapping会调用mapping的getHandler(exchange)方法,getHandler(exchange)方法的定义在HandlerMapping接口里,它的实现类只有一个,是AbstractHandlerMapping。getHandler(exchange)方法的源码如下:

@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;
   });
}

      getHandler(exchange)首先调用getHandlerInternal(exchange)方法获取handler,getHandlerInternal方法分散在不同类中,根据handlerMappings继承关系图,我画出了getHandlerInternal(exchange)方法的调用图,如下所示,红色的箭头是mappings方法调用的getHandlerInternal方法所处的位置。
在这里插入图片描述
      我们逐个看一下六个mapping bean调用的getHandlerInternal方法的源码,看一下内部是如何执行的,mapping.getHandler()到底使用的是哪个HandlerMapping。

4.1 RequestMappingInfoHandlerMapping.getHandlerInternal

      首先看RequestMappingInfoHandlerMapping,它调用了父类也就是AbstractHandlerMethodMapping的getHandlerInternal方法,代码如下:

@Override
public Mono<HandlerMethod> getHandlerInternal(ServerWebExchange exchange) {
   exchange.getAttributes().remove(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
   return super.getHandlerInternal(exchange) 此行
         .doOnTerminate(() -> ProducesRequestCondition.clearMediaTypesAttribute(exchange));
}

4.1.1 AbstractHandlerMethodMapping.getHandlerInternal

      AbstractHandlerMethodMapping.getHandlerInternal方法的源代码如下:

@Override
public Mono<HandlerMethod> getHandlerInternal(ServerWebExchange exchange) {
   this.mappingRegistry.acquireReadLock();
   try {
      HandlerMethod handlerMethod;
      try {
         handlerMethod = lookupHandlerMethod(exchange);//此行
      }
      catch (Exception ex) {
         return Mono.error(ex);
      }
      if (handlerMethod != null) {
         handlerMethod = handlerMethod.createWithResolvedBean();//此行
      }
      return Mono.justOrEmpty(handlerMethod);
   }
   finally {
      this.mappingRegistry.releaseReadLock();
   }
}

      这段代码有两处比较关键,一处是lookupHandlerMethod(exchange), 找到一个handlerMethod, 另一处调用了handlerMethod的createWithResolvedBean()方法,返回了一个新的handlerMethod。先来看一下lookupHandlerMethod(exchange)的实现细节,它的源代码如下:

protected HandlerMethod lookupHandlerMethod(ServerWebExchange exchange) throws Exception {
   List<Match> matches = new ArrayList<>();
   addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, exchange); //此行

   if (!matches.isEmpty()) {
      Comparator<Match> comparator = new MatchComparator(getMappingComparator(exchange));
      matches.sort(comparator);
      Match bestMatch = matches.get(0);
      if (matches.size() > 1) {
         if (logger.isTraceEnabled()) {
            logger.trace(exchange.getLogPrefix() + matches.size() + " matching mappings: " + matches);
         }
         if (CorsUtils.isPreFlightRequest(exchange.getRequest())) {
            return PREFLIGHT_AMBIGUOUS_MATCH;
         }
         Match secondBestMatch = matches.get(1);
         if (comparator.compare(bestMatch, secondBestMatch) == 0) {
            Method m1 = bestMatch.handlerMethod.getMethod();
            Method m2 = secondBestMatch.handlerMethod.getMethod();
            RequestPath path = exchange.getRequest().getPath();
            throw new IllegalStateException(
                  "Ambiguous handler methods mapped for '" + path + "': {" + m1 + ", " + m2 + "}");
         }
      }
      handleMatch(bestMatch.mapping, bestMatch.handlerMethod, exchange);
      return bestMatch.handlerMethod;
   }
   else {
      return handleNoMatch(this.mappingRegistry.getMappings().keySet(), exchange);
   }
}

      它首先调用addMatchingMappings方法,在matches里放入Match,并根据matches是否为空做进一步处理,如果不为空则返回handlerMethod,如果为空则调用handleNoMatch方法,handleNoMatch方法返回null,代表没有找打handler。

protected HandlerMethod handleNoMatch(Set<T> mappings, ServerWebExchange exchange) throws Exception {
   return null;
}

      在来看addMatchingMappings方法,它的第一个参数是this.mappingRegistry.getMappings().keySet(),那mappingRegistry是在哪初始化的呢,
初始化mappingRegistry有两处,代码如下所示:

public void registerMapping(T mapping, Object handler, Method method) {
   if (logger.isTraceEnabled()) {
      logger.trace("Register \"" + mapping + "\" to " + method.toGenericString());
   }
   this.mappingRegistry.register(mapping, handler, method);
}
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
   this.mappingRegistry.register(mapping, handler, method);
}

      这两处都是为了子类注册handler用的,我们逐个看下子类是怎样注册的。

4.1.1.1 子类RequestMappingInfoHandlerMapping的registerMapping

      子类RequestMappingInfoHandlerMapping 调用了父类的方法,也就是AbstractHandlerMethodMapping的registerMapping

@Override
public void registerMapping(RequestMappingInfo mapping, Object handler, Method method) {
   super.registerMapping(mapping, handler, method);
   updateConsumesCondition(mapping, method);
}
4.1.1.2 子类RequestMappingHandlerMapping的registerMapping

      子类RequestMappingHandlerMapping 也调用了父类的方法,也就是RequestMappingInfoHandlerMapping的registerMapping

@Override
public void registerMapping(RequestMappingInfo mapping, Object handler, Method method) {
   super.registerMapping(mapping, handler, method);
   updateConsumesCondition(mapping, method);
}
4.1.1.3 子类ControllerEndpointHandlerMapping的registerMapping

      子类ControllerEndpointHandlerMapping在registerHandlerMethod方法里调用了父类RequestMappingHandlerMapping的registerMapping方法。

@Override
protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
   ExposableControllerEndpoint endpoint = this.handlers.get(handler);
   mapping = withEndpointMappedPatterns(endpoint, mapping);
   super.registerHandlerMethod(handler, method, mapping);
}
4.1.1.4 子类AbstractWebMvcEndpointHandlerMapping的registerMapping

      子类AbstractWebMvcEndpointHandlerMapping通过initHandlerMethods方法注册registerMapping

@Override
protected void initHandlerMethods() {
   for (ExposableWebEndpoint endpoint : this.endpoints) {
      for (WebOperation operation : endpoint.getOperations()) {
         registerMappingForOperation(endpoint, operation);//此行
      }
   }
   if (this.shouldRegisterLinksMapping) {
      registerLinksMapping();
   }
}

private void registerMappingForOperation(ExposableWebEndpoint endpoint, WebOperation operation) {
   WebOperationRequestPredicate predicate = operation.getRequestPredicate();
   String path = predicate.getPath();
   String matchAllRemainingPathSegmentsVariable = predicate.getMatchAllRemainingPathSegmentsVariable();
   if (matchAllRemainingPathSegmentsVariable != null) {
      path = path.replace("{*" + matchAllRemainingPathSegmentsVariable + "}", "**");
   }
   ServletWebOperation servletWebOperation = wrapServletWebOperation(endpoint, operation,
         new ServletWebOperationAdapter(operation));
   registerMapping(createRequestMappingInfo(predicate, path), new OperationHandler(servletWebOperation),
         this.handleMethod);//此行
}

private void registerLinksMapping() {
   PatternsRequestCondition patterns = patternsRequestConditionForPattern("");
   RequestMethodsRequestCondition methods = new RequestMethodsRequestCondition(RequestMethod.GET);
   ProducesRequestCondition produces = new ProducesRequestCondition(this.endpointMediaTypes.getProduced()
         .toArray(StringUtils.toStringArray(this.endpointMediaTypes.getProduced())));
   RequestMappingInfo mapping = new RequestMappingInfo(patterns, methods, null, null, null, produces, null);
   LinksHandler linksHandler = getLinksHandler();
   registerMapping(mapping, linksHandler, ReflectionUtils.findMethod(linksHandler.getClass(), "links",
         HttpServletRequest.class, HttpServletResponse.class));//此行
}
4.1.1.5 子类AbstractWebFluxEndpointHandlerMapping的registerMapping

      子类AbstractWebFluxEndpointHandlerMapping注册registerMapping的方式与AbstractWebMvcEndpointHandlerMapping大同小异

@Override
protected void initHandlerMethods() {
   for (ExposableWebEndpoint endpoint : this.endpoints) {
      for (WebOperation operation : endpoint.getOperations()) {
         registerMappingForOperation(endpoint, operation);
      }
   }
   if (this.shouldRegisterLinksMapping) {
      registerLinksMapping();
   }
}

private void registerMappingForOperation(ExposableWebEndpoint endpoint, WebOperation operation) {
   ReactiveWebOperation reactiveWebOperation = wrapReactiveWebOperation(endpoint, operation,
         new ReactiveWebOperationAdapter(operation));
   if (operation.getType() == OperationType.WRITE) {
      registerMapping(createRequestMappingInfo(operation), new WriteOperationHandler((reactiveWebOperation)),
            this.handleWriteMethod);
   }
   else {
      registerMapping(createRequestMappingInfo(operation), new ReadOperationHandler((reactiveWebOperation)),
            this.handleReadMethod);
   }
}

private void registerLinksMapping() {
   PatternsRequestCondition patterns = new PatternsRequestCondition(
         pathPatternParser.parse(this.endpointMapping.getPath()));
   RequestMethodsRequestCondition methods = new RequestMethodsRequestCondition(RequestMethod.GET);
   ProducesRequestCondition produces = new ProducesRequestCondition(
         StringUtils.toStringArray(this.endpointMediaTypes.getProduced()));
   RequestMappingInfo mapping = new RequestMappingInfo(patterns, methods, null, null, null, produces, null);
   LinksHandler linksHandler = getLinksHandler();
   registerMapping(mapping, linksHandler,
         ReflectionUtils.findMethod(linksHandler.getClass(), "links", ServerWebExchange.class));
}

4.1.2 registerMapping方法触发时机

      这些类都继承了AbstractHandlerMethodMapping,AbstractHandlerMethodMapping实现了InitializingBean类,在afterPropertiesSet方法中触发了initHandlerMethods()方法的调用

@Override
public void afterPropertiesSet() {

   initHandlerMethods();//此行

   // Total includes detected mappings + explicit registrations via registerMapping..
   int total = this.getHandlerMethods().size();

   if ((logger.isTraceEnabled() && total == 0) || (logger.isDebugEnabled() && total > 0) ) {
      logger.debug(total + " mappings in " + formatMappingName());
   }
}

      initHandlerMethods()方法也在AbstractHandlerMethodMapping类中,被所有的子类继承,它的源代码如下:

protected void initHandlerMethods() {
   String[] beanNames = obtainApplicationContext().getBeanNamesForType(Object.class);

   for (String beanName : beanNames) {
      if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
         Class<?> beanType = null;
         try {
            beanType = obtainApplicationContext().getType(beanName);
         }
         catch (Throwable ex) {
            // An unresolvable bean type, probably from a lazy bean - let's ignore it.
            if (logger.isTraceEnabled()) {
               logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
            }
         }
         if (beanType != null && isHandler(beanType)) {
            detectHandlerMethods(beanName);//此行
         }
      }
   }
   handlerMethodsInitialized(getHandlerMethods());
}

      在这个方法中调用了detectHandlerMethods(beanName)方法,这个方法也在AbstractHandlerMethodMapping类中,被所有的子类继承,源代码如下:

protected void detectHandlerMethods(final Object handler) {
   Class<?> handlerType = (handler instanceof String ?
         obtainApplicationContext().getType((String) handler) : handler.getClass());

   if (handlerType != null) {
      final Class<?> userType = ClassUtils.getUserClass(handlerType);
      Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
            (MethodIntrospector.MetadataLookup<T>) method -> getMappingForMethod(method, userType));
      if (logger.isTraceEnabled()) {
         logger.trace(formatMappings(userType, methods));
      }
      methods.forEach((method, mapping) -> {
         Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
         registerHandlerMethod(handler, invocableMethod, mapping); //此行
      });
   }
}

      这个方法触发了registerHandlerMethod方法的调用,最终调用到registerMapping方法。

4.1.3 isHandler(beanType)

      initHandlerMethods方法的第16行有一个判断:isHandler(beanType),判断bean是否是Handler,如果是Handler则执行detectHandlerMethods方法。
      isHandler(beanType)方法的定义在AbstractHandlerMethodMapping中,它的实现类共有两个,一个在AbstractWebFluxEndpointHandlerMapping中,一个在RequestMappingHandlerMapping中,如下图所示。

if (beanType != null && isHandler(beanType)) {
      detectHandlerMethods(beanName);//此行
}

在这里插入图片描述
      AbstractWebFluxEndpointHandlerMapping的isHandler方法直接返回的false,由类继承关系图可知,类WebFluxEndpointHandlerMapping不是handler。

@Override
protected boolean isHandler(Class<?> beanType) {
   return false;
}

      RequestMappingHandlerMapping的isHandler方法判断bean上是否有Controller或者RequestMapping注解,我们用gateway,显然是不会标注这两个注解的,根据类继承关系图,RequestMappingHandlerMapping和其子类ControllerEndpointHandlerMapping也不是handler(仅在gateway的情况下,区别于webmvc的场景)。

@Override
protected boolean isHandler(Class<?> beanType) {
   return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
         AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

4.2 AbstractUrlHandlerMapping.getHandlerInternal

      AbstractUrlHandlerMapping.getHandlerInternal首先获取lookupPath,根据lookupPath获取handler,代码如下所示:

@Override
public Mono<Object> getHandlerInternal(ServerWebExchange exchange) {
   PathContainer lookupPath = exchange.getRequest().getPath().pathWithinApplication();
   Object handler;
   try {
      handler = lookupHandler(lookupPath, exchange);//此行
   }
   catch (Exception ex) {
      return Mono.error(ex);
   }
   return Mono.justOrEmpty(handler);
}

      lookupHandler方法的源代码如下所示,根据handlerMap获取PathPattern list,根据list做相关处理,如果list为空返回null,表示未找到handler,
如果不为空,则找到handler。

@Nullable
protected Object lookupHandler(PathContainer lookupPath, ServerWebExchange exchange) throws Exception {

   List<PathPattern> matches = this.handlerMap.keySet().stream()
         .filter(key -> key.matches(lookupPath))
         .collect(Collectors.toList());

   if (matches.isEmpty()) {
      return null;
   }

   if (matches.size() > 1) {
      matches.sort(PathPattern.SPECIFICITY_COMPARATOR);
      if (logger.isTraceEnabled()) {
         logger.debug(exchange.getLogPrefix() + "Matching patterns " + matches);
      }
   }

   PathPattern pattern = matches.get(0);
   PathContainer pathWithinMapping = pattern.extractPathWithinPattern(lookupPath);
   return handleMatch(this.handlerMap.get(pattern), pattern, pathWithinMapping, exchange);
}

4.2.1 handlerMap加载

      handlerMap的初始化在SimpleUrlHandlerMapping类中,由类的继承关系图可知,SimpleUrlHandlerMapping继承自ApplicationObjectSupport,ApplicationObjectSupport实现自ApplicationContextAware,在ApplicationObjectSupport中触发了initApplicationContext的加载

@Override
public final void setApplicationContext(@Nullable ApplicationContext context) throws BeansException {
   if (context == null && !isContextRequired()) {
      // Reset internal context state.
      this.applicationContext = null;
      this.messageSourceAccessor = null;
   }
   else if (this.applicationContext == null) {
      // Initialize with passed-in context.
      if (!requiredContextClass().isInstance(context)) {
         throw new ApplicationContextException(
               "Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]");
      }
      this.applicationContext = context;
      this.messageSourceAccessor = new MessageSourceAccessor(context);
      initApplicationContext(context);//此行
   }
   else {
      // Ignore reinitialization if same context passed in.
      if (this.applicationContext != context) {
         throw new ApplicationContextException(
               "Cannot reinitialize with different application context: current one is [" +
               this.applicationContext + "], passed-in one is [" + context + "]");
      }
   }
}

@Override
public void initApplicationContext() throws BeansException {
   super.initApplicationContext();
   registerHandlers(this.urlMap);
}

4.2.2 urlMap初始化

      不同的场景,有不同的初始化urlMap的方式,WebFlux是在WebFluxConfigurationSupport类中,WebMvc是在WebMvcConfigurationSupport类中,初始化逻辑大同小异,先看下WebFluxConfigurationSupport中是如何初始化的,初始化的bean代码如下:

@Bean
public HandlerMapping resourceHandlerMapping(ResourceUrlProvider resourceUrlProvider) {
   ResourceLoader resourceLoader = this.applicationContext;
   if (resourceLoader == null) {
      resourceLoader = new DefaultResourceLoader();
   }
   ResourceHandlerRegistry registry = new ResourceHandlerRegistry(resourceLoader);
   registry.setResourceUrlProvider(resourceUrlProvider);
   addResourceHandlers(registry);
   //此行获取的就是SimpleURLHandlerMapping 
   AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
   if (handlerMapping != null) {
      PathMatchConfigurer configurer = getPathMatchConfigurer();
      Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
      Boolean useCaseSensitiveMatch = configurer.isUseCaseSensitiveMatch();
      if (useTrailingSlashMatch != null) {
         handlerMapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
      }
      if (useCaseSensitiveMatch != null) {
         handlerMapping.setUseCaseSensitiveMatch(useCaseSensitiveMatch);
      }
   }
   else {
      handlerMapping = new EmptyHandlerMapping();
   }
   return handlerMapping;
}

      WebMvcConfigurationSupport类中是这样初始化的:

@Bean
@Nullable
public HandlerMapping viewControllerHandlerMapping(
      @Qualifier("mvcPathMatcher") PathMatcher pathMatcher,
      @Qualifier("mvcUrlPathHelper") UrlPathHelper urlPathHelper,
      @Qualifier("mvcConversionService") FormattingConversionService conversionService,
      @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
   ViewControllerRegistry registry = new ViewControllerRegistry(this.applicationContext);
   addViewControllers(registry);

   AbstractHandlerMapping handlerMapping = registry.buildHandlerMapping();//
   if (handlerMapping == null) {
      return null;
   }
   handlerMapping.setPathMatcher(pathMatcher);
   handlerMapping.setUrlPathHelper(urlPathHelper);
   handlerMapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
   handlerMapping.setCorsConfigurations(getCorsConfigurations());
   return handlerMapping;
}

      我们在使用gateway的时候,显然不会配置url和handler的映射关系,所以SimpleUrlHandlerMapping也不是DispatcherHandler.handle()方法中使用的handler。

4.3 RouterFunctionMapping.getHandlerInternal

      RouterFunctionMapping.getHandlerInternal根据routerFunction是否为空做下一步处理,当routerFunction为空时返回空的Mono,不为空时调用routerFunction的route方法处理请求,代码如下所示:

@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
   if (this.routerFunction != null) {
      ServerRequest request = ServerRequest.create(exchange, this.messageReaders);
      return this.routerFunction.route(request)
            .doOnNext(handler -> setAttributes(exchange.getAttributes(), request, handler));
   }
   else {
      return Mono.empty();
   }
}

4.3.1 routerFunction的初始化

      由HandlerMapping继承关系图可知,RouterFunctionMapping实现了InitializingBean,routerFunction的初始化在RouterFunctionMapping覆写的afterPropertiesSet方法中,它调用了initRouterFunctions()方法。

@Override
public void afterPropertiesSet() throws Exception {
   if (CollectionUtils.isEmpty(this.messageReaders)) {
      ServerCodecConfigurer codecConfigurer = ServerCodecConfigurer.create();
      this.messageReaders = codecConfigurer.getReaders();
   }
   if (this.routerFunction == null) {
      initRouterFunctions();
   }
}

      initRouterFunctions方法如下所示,从routerFunctions()方法获取RouterFunction list

protected void initRouterFunctions() {
   List<RouterFunction<?>> routerFunctions = routerFunctions();
   this.routerFunction = routerFunctions.stream().reduce(RouterFunction::andOther).orElse(null);
   logRouterFunctions(routerFunctions);
}

      routerFunctions方法获取所有RouterFunction类型的bean,并组织成List返回,代码如下所示:

private List<RouterFunction<?>> routerFunctions() {
   List<RouterFunction<?>> functions = obtainApplicationContext()
         .getBeanProvider(RouterFunction.class)
         .orderedStream()
         .map(router -> (RouterFunction<?>)router)
         .collect(Collectors.toList());
   return (!CollectionUtils.isEmpty(functions) ? functions : Collections.emptyList());
}

4.3.2 RouterFunction构造

      RouterFunction是Spring Framework 5中的概念,RouterFunction以如下所示的代码的方式构建。

@Bean
public RouterFunction<ServerResponse> initRouterFunction(){
    return RouterFunctions.route()
        .GET("/hello/**",serverRequest -> {
            System.out.println("path:"+serverRequest.exchange().getRequest().getPath().pathWithinApplication().value());
            return ServerResponse.ok().bodyValue("hello world");
        })
        .filter((serverRequest, handlerFunction) -> {
            System.out.println("hello world test");
            return handlerFunction.handle(serverRequest);
        })
        .build();

}

      我们gateway里没有这种方式。

4.4 RoutePredicateHandlerMapping.getHandlerInternal

      RoutePredicateHandlerMapping.getHandlerInternal首先调用lookupRoute函数,接下来通过flatMap把Route转换成了Mono,也就是return Mono.just(webHandler),这里的webHandler是FilteringWebHandler,源代码如下:

private final FilteringWebHandler webHandler;

@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
   // 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();
   }
   exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());

   return lookupRoute(exchange)
         // .log("route-predicate-handler-mapping", Level.FINER) //name this
         .flatMap((Function<Route, Mono<?>>) r -> {
            exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
            if (logger.isDebugEnabled()) {
               logger.debug(
                     "Mapping [" + getExchangeDesc(exchange) + "] to " + r);
            }

            exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
            return Mono.just(webHandler);
         }).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
            exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
            if (logger.isTraceEnabled()) {
               logger.trace("No RouteDefinition found for ["
                     + getExchangeDesc(exchange) + "]");
            }
         })));
}

4.4.1 lookupRoute(exchange)

      lookupRoute从routeLocator中迭代route,并返回第一个满足断言的route,源代码如下所示:

protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
   return this.routeLocator.getRoutes()
         // individually filter routes so that filterWhen error delaying is not a
         // problem
         .concatMap(route -> Mono.just(route).filterWhen(r -> {
            // add the current route we are testing
            exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
            return r.getPredicate().apply(exchange);
         })
               // instead of immediately stopping main flux due to error, log and
               // swallow it
               .doOnError(e -> logger.error(
                     "Error applying predicate for route: " + route.getId(),
                     e))
               .onErrorResume(e -> Mono.empty()))
         // .defaultIfEmpty() put a static Route not found
         // or .switchIfEmpty()
         // .switchIfEmpty(Mono.<Route>empty().log("noroute"))
         .next()
         // TODO: error handling
         .map(route -> {
            if (logger.isDebugEnabled()) {
               logger.debug("Route matched: " + route.getId());
            }
            validateRoute(route, exchange);
            return route;
         });

   /*
    * TODO: trace logging if (logger.isTraceEnabled()) {
    * logger.trace("RouteDefinition did not match: " + routeDefinition.getId()); }
    */
}

4.4.2 routeLocator初始化

      routeLocator在初始化RoutePredicateHandlerMapping构造函数初始化,代码如下:

public RoutePredicateHandlerMapping(FilteringWebHandler webHandler,
      RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties,
      Environment environment) {
   this.webHandler = webHandler;
   this.routeLocator = routeLocator;
   this.managementPort = getPortProperty(environment, "management.server.");
   this.managementPortType = getManagementPortType(environment);
   setOrder(1);
   setCorsConfigurations(globalCorsProperties.getCorsConfigurations());
}

      构造函数在GateAutoConfiguration自动装配类中,作为bean初始化

@Bean
public RoutePredicateHandlerMapping routePredicateHandlerMapping(
      FilteringWebHandler webHandler, RouteLocator routeLocator,
      GlobalCorsProperties globalCorsProperties, Environment environment) {
   return new RoutePredicateHandlerMapping(webHandler, routeLocator,
         globalCorsProperties, environment);
}

      初始化时第二个参数RouteLocator的初始化也在GatewayAutoConfiguration中,注意@primary注解,这是gateway使用的RouteLocator。

@Bean
@Primary
@ConditionalOnMissingBean(name = "cachedCompositeRouteLocator")
// TODO: property to disable composite?
public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
   return new CachingRouteLocator(
         new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
}

      它上的参数List是RouteDefinitionRouteLocator类的实例。

@Bean
public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,
      List<GatewayFilterFactory> gatewayFilters,
      List<RoutePredicateFactory> predicates,
      RouteDefinitionLocator routeDefinitionLocator,
      ConfigurationService configurationService) {
   return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates,
         gatewayFilters, properties, configurationService);
}

      这个类需要五个参数
      1. GatewayProperties读取的是前缀为“spring.cloud.gateway”的gateway的yaml配置文件。
      2. List GatewayFilterFactory的bean初始化在GatewayAutoConfiguration类中。
      3. List predicates的初始化也在GatewayAutoConfiguration类中。
      4. RouteDefinitionLocator 读取的是接口路由配置文件。
      5. ConfigurationService 主要一些系统级别的信息,beanFactory、Conversion、Validator等,它的bean定义如下:

@Bean
public ConfigurationService gatewayConfigurationService(BeanFactory beanFactory,
      @Qualifier("webFluxConversionService") ObjectProvider<ConversionService> conversionService,
      ObjectProvider<Validator> validator) {
   return new ConfigurationService(beanFactory, conversionService, validator);
}

      由此可知,gateway使用的handlerMapping为RoutePredicateHandlerMapping。

5. 总结

      本篇文章通过分析源码的形式,分析了mapping.getHandler(exchange)的实现原理。
得出getHandler(exchange)内部方法getHandlerInternal(exchange)调用的是RoutePredicateHandlerMapping的实现。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐