文章目录

  • 1. 概览
  • 2. handle方法回顾
  • 3.handlerMappings获取
  • 4.HandlerMapping初始化
  • 4.1 WebFluxEndpointHandlerMapping 初始化
  • 4.1.1 WebFluxEndpointManagementContextConfiguration
  • 4.2 ControllerEndpointHandlerMapping
  • 4.3 RouterFuntionMapping 初始化
  • 4.4 RequestMappingHandlerMapping初始化
  • 4.5 RoutePredicateHandlerMapping 初始化
  • 4.6 SimpleUrlHandlerMapping的初始化
  • 4.6.1 WebMvcAutoConfiguration
  • 5. 总结


1. 概览

      上一节分享到了gateway的入口DispatcherHandler.handle()方法,本节分享handle方法的实现原理。由于handle方法步骤较多,本节只分享handlerMappings的获取。

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

      handle方法处理请求总共分为四部分,首先通过handlerMappings找到请求对应的handlerMapping,第二步通过handlerMappings找到对应的handler方法,第三步调用handler方法获取到结果,最后通过handleResult方法处理结果。本节主要分享handlerMapping是如何组织的。

3.handlerMappings获取

      handlerMappings是在initStrategies方法中初始化的,通过BeanFactoryUtils获取到所有HandlerMapping类型的Bean,代码如下:

protected void initStrategies(ApplicationContext context) {
   Map<String, HandlerMapping> mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
         context, HandlerMapping.class, true, false);
   ArrayList<HandlerMapping> mappings = new ArrayList<>(mappingBeans.values());
   AnnotationAwareOrderComparator.sort(mappings);
   this.handlerMappings = Collections.unmodifiableList(mappings);


   Map<String, HandlerAdapter> adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
         context, HandlerAdapter.class, true, false);
   this.handlerAdapters = new ArrayList<>(adapterBeans.values());
   AnnotationAwareOrderComparator.sort(this.handlerAdapters);


   Map<String, HandlerResultHandler> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
         context, HandlerResultHandler.class, true, false);
   this.resultHandlers = new ArrayList<>(beans.values());
   AnnotationAwareOrderComparator.sort(this.resultHandlers);
}

      那都获得了那些handlerMappings呢,在我的项目中,我通过debug发现,handlerMappings List里一共有6个对象,分别是

      1. WebFluxEndpointHandlerMapping

      2. ControllerEndpointHandlerMapping

      3. RouterFunctionMapping

      4. RequestMappingHandlerMapping

      5. RoutePredicateHandlerMapping

      6. SimpleUrlHandlerMapping

Java中Controller方法用map接参_初始化


      他们有什么作用,以及是何时被初始化的呢,接下来我们一个一个探索一下。

4.HandlerMapping初始化

4.1 WebFluxEndpointHandlerMapping 初始化

      WebFluxEndpointHandlerMapping的初始化在WebFluxEndpointManagementContextConfiguration类中,类声明如下:

@ManagementContextConfiguration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.REACTIVE)
@ConditionalOnClass({ DispatcherHandler.class, HttpHandler.class })
@ConditionalOnBean(WebEndpointsSupplier.class)
@EnableConfigurationProperties(CorsEndpointProperties.class)
public class WebFluxEndpointManagementContextConfiguration {

      WebFluxEndpointHandlerMapping注册bean代码如下

@Bean
@ConditionalOnMissingBean
public WebFluxEndpointHandlerMapping webEndpointReactiveHandlerMapping(WebEndpointsSupplier webEndpointsSupplier,
      ControllerEndpointsSupplier controllerEndpointsSupplier, EndpointMediaTypes endpointMediaTypes,
      CorsEndpointProperties corsProperties, WebEndpointProperties webEndpointProperties,
      Environment environment) {
   String basePath = webEndpointProperties.getBasePath();
   EndpointMapping endpointMapping = new EndpointMapping(basePath);
   Collection<ExposableWebEndpoint> endpoints = webEndpointsSupplier.getEndpoints();
   List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
   allEndpoints.addAll(endpoints);
   allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
   return new WebFluxEndpointHandlerMapping(endpointMapping, endpoints, endpointMediaTypes,
         corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath),
         shouldRegisterLinksMapping(environment, basePath));
}

4.1.1 WebFluxEndpointManagementContextConfiguration

      WebFluxEndpointManagementContextConfiguration这个类不在spring-cloud-gateway-server包中,它在spring-boot-actuator-autoconfigure包中,是spring.factories文件指定的自动装配类

Java中Controller方法用map接参_spring_02

4.2 ControllerEndpointHandlerMapping

      ControllerEndpointHandlerMapping类的初始化也在WebFluxEndpointManagementContextConfiguration类中,代码如下:

@Bean
@ConditionalOnMissingBean
public ControllerEndpointHandlerMapping controllerEndpointHandlerMapping(
      ControllerEndpointsSupplier controllerEndpointsSupplier, CorsEndpointProperties corsProperties,
      WebEndpointProperties webEndpointProperties) {
   EndpointMapping endpointMapping = new EndpointMapping(webEndpointProperties.getBasePath());
   return new ControllerEndpointHandlerMapping(endpointMapping, controllerEndpointsSupplier.getEndpoints(),
         corsProperties.toCorsConfiguration());
}

4.3 RouterFuntionMapping 初始化

      RouterFuntionMapping的初始化在WebFluxAutoConfiguration的内部类WelcomePageConfiguration里
WebFluxAutoConfiguration在GatewayAutoConfiguration里触发加载,代码如下

@AutoConfigureBefore({ HttpHandlerAutoConfiguration.class,
      WebFluxAutoConfiguration.class })

      WebFluxAutoConfiguration类声明如下:

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnClass(WebFluxConfigurer.class)
@ConditionalOnMissingBean({ WebFluxConfigurationSupport.class })
@AutoConfigureAfter({ ReactiveWebServerFactoryAutoConfiguration.class, CodecsAutoConfiguration.class,
      ValidationAutoConfiguration.class })
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
public class WebFluxAutoConfiguration {

      RouterFunctionMapping 加载代码如下:

@Configuration(proxyBeanMethods = false)
public static class WelcomePageConfiguration {

   @Bean
   public RouterFunctionMapping welcomePageRouterFunctionMapping(ApplicationContext applicationContext,
         WebFluxProperties webFluxProperties, ResourceProperties resourceProperties) {
      WelcomePageRouterFunctionFactory factory = new WelcomePageRouterFunctionFactory(
            new TemplateAvailabilityProviders(applicationContext), applicationContext,
            resourceProperties.getStaticLocations(), webFluxProperties.getStaticPathPattern());
      RouterFunction<ServerResponse> routerFunction = factory.createRouterFunction();
      if (routerFunction != null) {
         RouterFunctionMapping routerFunctionMapping = new RouterFunctionMapping(routerFunction);
         routerFunctionMapping.setOrder(1);
         return routerFunctionMapping;
      }
      return null;
   }
}

      除了RouterFunctionMapping,WebFluxAutoConfiguration还加载了另外两个重要的配置ResourceProperties 和 WebFluxProperties 用来加载WebFlux配置使用。

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({ ResourceProperties.class, WebFluxProperties.class })
@Import({ EnableWebFluxConfiguration.class })
public static class WebFluxConfig implements WebFluxConfigurer {

4.4 RequestMappingHandlerMapping初始化

      RequestMappingHandlerMapping 在 WebFluxConfigurationSupport中被实例化,代码如下:

@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping(
      @Qualifier("webFluxContentTypeResolver") RequestedContentTypeResolver contentTypeResolver) {

   RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
   mapping.setOrder(0);
   mapping.setContentTypeResolver(contentTypeResolver);
   mapping.setCorsConfigurations(getCorsConfigurations());

   PathMatchConfigurer configurer = getPathMatchConfigurer();
   Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
   if (useTrailingSlashMatch != null) {
      mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
   }
   Boolean useCaseSensitiveMatch = configurer.isUseCaseSensitiveMatch();
   if (useCaseSensitiveMatch != null) {
      mapping.setUseCaseSensitiveMatch(useCaseSensitiveMatch);
   }
   Map<String, Predicate<Class<?>>> pathPrefixes = configurer.getPathPrefixes();
   if (pathPrefixes != null) {
      mapping.setPathPrefixes(pathPrefixes);
   }

   return mapping;
}

      WebFluxConfigurationSupport 在GatewayAutoConfiguration类中,由注解

@AutoConfigureBefore({ HttpHandlerAutoConfiguration.class,
      WebFluxAutoConfiguration.class })

      注入到spring中.

4.5 RoutePredicateHandlerMapping 初始化

      RoutePredicateHandlerMapping 是在GatewayAutoConfiguration类中初始化。
      RoutePredicateHandlerMapping声明的代码如下:

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

      从RoutePredicateHandlerMapping初始化的类我判断handle方法使用的mapping应该是它。

4.6 SimpleUrlHandlerMapping的初始化

      SimpleUrlHandlerMapping的初始化在WebMvcAutoConfiguration类中,我们先来看一下这个类,类上面声明了好多的注解,其中@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class }) 可以看到,它是用来处理mvc请求的。

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
      ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {

      具体实例化的代码如下所示,在第14行调用registry.getHandlerMapping()获得了一个mapping,这个mapping就是SimpleUrlHandlerMapping

@Bean
@Override
public HandlerMapping resourceHandlerMapping(@Qualifier("mvcUrlPathHelper") UrlPathHelper urlPathHelper,
      @Qualifier("mvcPathMatcher") PathMatcher pathMatcher,
      @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
      @Qualifier("mvcConversionService") FormattingConversionService conversionService,
      @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
   Assert.state(getApplicationContext() != null, "No ApplicationContext set");
   Assert.state(getServletContext() != null, "No ServletContext set");
   AutoConfigurationResourceHandlerRegistry registry = new AutoConfigurationResourceHandlerRegistry(
         getApplicationContext(), getServletContext(), contentNegotiationManager, urlPathHelper,
         this.mvcProperties);
   addResourceHandlers(registry); //增加了registry
   AbstractHandlerMapping mapping = registry.getHandlerMapping(); //
   if (mapping == null) {
      return null;
   }
   mapping.setPathMatcher(pathMatcher);
   mapping.setUrlPathHelper(urlPathHelper);
   mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
   mapping.setCorsConfigurations(getCorsConfigurations());
   return mapping;
}

      registry.getHandlerMapping()方法如下所示

@Override
protected AbstractHandlerMapping getHandlerMapping() {
   SimpleUrlHandlerMapping mapping = (SimpleUrlHandlerMapping) super.getHandlerMapping();
   reconfigure(mapping);
   return mapping;
}

4.6.1 WebMvcAutoConfiguration

      WebMvcAutoConfiguration类也不在spring-cloud-gateway-server中,它在spring-boot-autoconfigure包中,它是这个包中spring.factories文件中指定的自动装配类

Java中Controller方法用map接参_servlet_03

5. 总结

      最后我们总结一下这些handlerMappings的初始化时机。

Java中Controller方法用map接参_java_04