4. gateway入口 handle方法详解-handlerMappings获取

本文详细解析了Spring Cloud Gateway中handlerMappings的获取机制,涉及WebFluxEndpointHandlerMapping、ControllerEndpointHandlerMapping、RouterFunctionMapping、RequestMappingHandlerMapping和RoutePredicateHandlerMapping等关键组件的初始化源码和应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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
在这里插入图片描述
      他们有什么作用,以及是何时被初始化的呢,接下来我们一个一个探索一下。

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文件指定的自动装配类
在这里插入图片描述

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文件中指定的自动装配类
在这里插入图片描述

5. 总结

      最后我们总结一下这些handlerMappings的初始化时机。
在这里插入图片描述

### Spring Cloud Gateway Global Filters 配置属性解析问题 Spring Cloud Gateway 提供了一种灵活的方式来定义全局过滤器(Global Filters),这些过滤器可以应用于所有的路由请求。然而,在配置 `global-filters` 属性时,可能会遇到一些常见的错误,比如无法正确加载或解析配置文件中的参数。 以下是针对 **Spring Cloud Gateway global-filters 配置属性解析问题** 的解决方案: #### 1. 确认 Configuration 文件格式 确保在 `application.yml` 或 `application.properties` 中的配置语法正确无误。YAML 文件尤其需要注意缩进和大小写敏感性[^1]。如果 YAML 缩进不一致或者键名拼写有误,则可能导致属性未被识别。 ```yaml spring: cloud: gateway: globalcors: add-to-simple-url-handler-mapping: true globalfilters: - name: AddRequestHeader args: headerName: X-Request-Foo headerValue: Foo-Bar ``` 上述示例展示了如何通过 YML 定义名为 `AddRequestHeader` 的全局过滤器及其参数设置。注意这里的嵌套结构以及冒号后的空格不可省略[^2]。 #### 2. 使用自定义 Bean 注册 Filter 当内置 filter 不满足需求时,可以通过 Java Config 创建并注册新的 bean 来实现更复杂的逻辑处理。下面是一个简单的例子展示怎样声明一个定制化的 PreFilter 并将其加入到上下文中去自动生效: ```java import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; @Component public class CustomGatewayConfiguration { @Bean public GatewayFilter customPreFilter() { return (exchange, chain) -> { exchange.getRequest().mutate() .header("X-Custom-Header", "Custom Value"); return chain.filter(exchange); }; } } ``` 此方法绕过了 yaml/json 格式的静态描述方式而直接采用编程手段动态构建对象实例,因此不会受到外部资源配置失败的影响[^3]。 #### 3. 调试与日志排查 开启调试模式可以帮助定位具体哪个环节出了差错。增加如下内容至 application.* 文件中启用详细的跟踪记录功能: ```properties logging.level.org.springframework.cloud.gateway=DEBUG management.endpoints.web.exposure.include=gateway ``` 这样可以在控制台看到更多关于网关内部运作的信息流输出,从而便于发现潜在隐患所在之处[^4]。 --- #### 总结 以上介绍了三种主要途径来应对 spring cloud gateway global filters configuration property resolution errors 方面挑战的方法论:一是核查基础设定文档是否存在低级失误;二是借助编码技巧规避依赖于字符串匹配的风险;三是利用增强型诊断工具辅助分析深层次原因。希望这些建议能够帮助您顺利解决问题!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值