本文主要研究一下spring cloud gateway的GlobalFilter

GatewayAutoConfiguration

spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java

@Configuration
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
@EnableConfigurationProperties
@AutoConfigureBefore(HttpHandlerAutoConfiguration.class)
@AutoConfigureAfter({GatewayLoadBalancerClientAutoConfiguration.class, GatewayClassPathWarningAutoConfiguration.class})
@ConditionalOnClass(DispatcherHandler.class)
public class GatewayAutoConfiguration {//......@Beanpublic FilteringWebHandler filteringWebHandler(List<GlobalFilter> globalFilters) {return new FilteringWebHandler(globalFilters);}@Beanpublic RoutePredicateHandlerMapping routePredicateHandlerMapping(FilteringWebHandler webHandler,RouteLocator routeLocator) {return new RoutePredicateHandlerMapping(webHandler, routeLocator);}//......
}
复制代码
  • 这里将globalFilters(NettyWriteResponseFilter、ForwardPathFilter、RouteToRequestUrlFilter、LoadBalancerClientFilter、AdaptCachedBodyGlobalFilter、WebsocketRoutingFilter、NettyRoutingFilter、ForwardRoutingFilter)作为构造器参数创建了FilteringWebHandler
  • 而依据FilteringWebHandler和RouteLocator创建了RoutePredicateHandlerMapping,这里的RouteLocator是CachingRouteLocator

FilteringWebHandler

spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/handler/FilteringWebHandler.java

/*** WebHandler that delegates to a chain of {@link GlobalFilter} instances and* {@link GatewayFilterFactory} instances then to the target {@link WebHandler}.** @author Rossen Stoyanchev* @author Spencer Gibb* @since 0.1*/
public class FilteringWebHandler implements WebHandler {protected static final Log logger = LogFactory.getLog(FilteringWebHandler.class);private final List<GatewayFilter> globalFilters;public FilteringWebHandler(List<GlobalFilter> globalFilters) {this.globalFilters = loadFilters(globalFilters);}private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {return filters.stream().map(filter -> {GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter);if (filter instanceof Ordered) {int order = ((Ordered) filter).getOrder();return new OrderedGatewayFilter(gatewayFilter, order);}return gatewayFilter;}).collect(Collectors.toList());}/* TODO: relocate @EventListener(RefreshRoutesEvent.class)void handleRefresh() {this.combinedFiltersForRoute.clear();}*/@Overridepublic Mono<Void> handle(ServerWebExchange exchange) {Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);List<GatewayFilter> gatewayFilters = route.getFilters();List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);combined.addAll(gatewayFilters);//TODO: needed or cached?AnnotationAwareOrderComparator.sort(combined);logger.debug("Sorted gatewayFilterFactories: "+ combined);return new DefaultGatewayFilterChain(combined).filter(exchange);}//......
}
复制代码
  • 这里在构造器里头调用loadFilters方法把List转换为List
  • 之后的handle方法,把选定的route的gatewayFilters与转换后的gatewayFilters合并,然后重新排序
  • 之后使用合并后的gatewayFilters创建DefaultGatewayFilterChain,挨个filter下去

GatewayFilterAdapter

  private static class GatewayFilterAdapter implements GatewayFilter {private final GlobalFilter delegate;public GatewayFilterAdapter(GlobalFilter delegate) {this.delegate = delegate;}@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {return this.delegate.filter(exchange, chain);}@Overridepublic String toString() {final StringBuilder sb = new StringBuilder("GatewayFilterAdapter{");sb.append("delegate=").append(delegate);sb.append('}');return sb.toString();}}
复制代码

这里将GlobalFilter适配为GatewayFilter,最后调用filter方法

DefaultGatewayFilterChain

   private static class DefaultGatewayFilterChain implements GatewayFilterChain {private final int index;private final List<GatewayFilter> filters;public DefaultGatewayFilterChain(List<GatewayFilter> filters) {this.filters = filters;this.index = 0;}private DefaultGatewayFilterChain(DefaultGatewayFilterChain parent, int index) {this.filters = parent.getFilters();this.index = index;}public List<GatewayFilter> getFilters() {return filters;}@Overridepublic Mono<Void> filter(ServerWebExchange exchange) {return Mono.defer(() -> {if (this.index < filters.size()) {GatewayFilter filter = filters.get(this.index);DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this, this.index + 1);return filter.filter(exchange, chain);} else {return Mono.empty(); // complete}});}}
复制代码

这里使用了责任链模式,里头filter方法,挨个遍历执行,传入的chain包含了当前的index,用于控制跳出责任链

RoutePredicateHandlerMapping

spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/handler/RoutePredicateHandlerMapping.java

public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {private final FilteringWebHandler webHandler;private final RouteLocator routeLocator;public RoutePredicateHandlerMapping(FilteringWebHandler webHandler, RouteLocator routeLocator) {this.webHandler = webHandler;this.routeLocator = routeLocator;setOrder(1);}@Overrideprotected Mono<?> getHandlerInternal(ServerWebExchange exchange) {exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getClass().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) + "]");}})));}@Overrideprotected CorsConfiguration getCorsConfiguration(Object handler, ServerWebExchange exchange) {//TODO: support cors configuration via global properties and// properties on a route see gh-229// see RequestMappingHandlerMapping.initCorsConfiguration()// also see https://github.com/spring-projects/spring-framework/blob/master/spring-web/src/test/java/org/springframework/web/cors/reactive/CorsWebFilterTests.javareturn super.getCorsConfiguration(handler, exchange);}//......
}
复制代码

这个RoutePredicateHandlerMapping主要是实现了父类的getHandlerInternal

DispatcherHandler

spring-webflux-5.0.6.RELEASE-sources.jar!/org/springframework/web/reactive/DispatcherHandler.java

/*** Central dispatcher for HTTP request handlers/controllers. Dispatches to* registered handlers for processing a request, providing convenient mapping* facilities.** <p>{@code DispatcherHandler} discovers the delegate components it needs from* Spring configuration. It detects the following in the application context:* <ul>* <li>{@link HandlerMapping} -- map requests to handler objects* <li>{@link HandlerAdapter} -- for using any handler interface* <li>{@link HandlerResultHandler} -- process handler return values* </ul>** <p>{@code DispatcherHandler} is also designed to be a Spring bean itself and* implements {@link ApplicationContextAware} for access to the context it runs* in. If {@code DispatcherHandler} is declared with the bean name "webHandler"* it is discovered by {@link WebHttpHandlerBuilder#applicationContext} which* creates a processing chain together with {@code WebFilter},* {@code WebExceptionHandler} and others.** <p>A {@code DispatcherHandler} bean declaration is included in* {@link org.springframework.web.reactive.config.EnableWebFlux @EnableWebFlux}* configuration.** @author Rossen Stoyanchev* @author Sebastien Deleuze* @author Juergen Hoeller* @since 5.0* @see WebHttpHandlerBuilder#applicationContext(ApplicationContext)*/
public class DispatcherHandler implements WebHandler, ApplicationContextAware {@SuppressWarnings("ThrowableInstanceNeverThrown")private static final Exception HANDLER_NOT_FOUND_EXCEPTION =new ResponseStatusException(HttpStatus.NOT_FOUND, "No matching handler");private static final Log logger = LogFactory.getLog(DispatcherHandler.class);@Nullableprivate List<HandlerMapping> handlerMappings;@Nullableprivate List<HandlerAdapter> handlerAdapters;@Nullableprivate List<HandlerResultHandler> resultHandlers;//......@Overridepublic void setApplicationContext(ApplicationContext applicationContext) {initStrategies(applicationContext);}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);}@Overridepublic Mono<Void> handle(ServerWebExchange exchange) {if (logger.isDebugEnabled()) {ServerHttpRequest request = exchange.getRequest();logger.debug("Processing " + request.getMethodValue() + " request for [" + request.getURI() + "]");}if (this.handlerMappings == null) {return Mono.error(HANDLER_NOT_FOUND_EXCEPTION);}return Flux.fromIterable(this.handlerMappings).concatMap(mapping -> mapping.getHandler(exchange)).next().switchIfEmpty(Mono.error(HANDLER_NOT_FOUND_EXCEPTION)).flatMap(handler -> invokeHandler(exchange, handler)).flatMap(result -> handleResult(exchange, result));}//......
}
复制代码
  • 这里setApplicationContext的时候调用了initStrategies方法
  • 使用BeanFactoryUtils.beansOfTypeIncludingAncestors获取了容器中注册的HandlerMapping
  • RoutePredicateHandlerMapping注册到了容器中,这里会被获取到
  • handlerMapping用于根据exchange来获取handler
  • 这了使用的是concatMap,如果返回的是Mono.empty()则不会被concat,然后next取第一个,即按handlerMappings排序之后的第一个来

handlerMappings

这里按优先级从高到底有如下几个:

  • WebFluxEndpointHandlerMapping(order=-100)
  • ControllerEndpointHandlerMapping(order=-100)
  • RouterFunctionMapping(order=-1)
  • RequestMappingHandlerMapping(order=0)
  • RoutePredicateHandlerMapping(order=1)
  • SimpleUrlHandlerMapping(Ordered.LOWEST_PRECEDENCE)

小结

spring cloud gateway的GlobalFilter在FilteringWebHandler被适配为GatewayFilter,然后与route级别的gatewayFilters进行合并,作用在当前route上面。RoutePredicateHandlerMapping会被DispatcherHandler识别,按order优先级排序,依次根据mapping来获取该exchange的handler,找到不是Mono.empty()的第一个,然后进行invokeHandler以及handleResult。

因此可以理解为GlobalFilter就是全局的GatewayFilter,作用在所有route上面。而GatewayFilter是route级别的。

doc

  • 113. Global Filters
  • 聊聊spring cloud gateway的RouteLocator

聊聊spring cloud gateway的GlobalFilter相关推荐

  1. 聊聊spring cloud gateway的PreserveHostHeaderGatewayFilter

    序 本文主要研究下spring cloud gateway的PreserveHostHeaderGatewayFilter GatewayAutoConfiguration spring-cloud- ...

  2. 聊聊spring cloud gateway的SecureHeadersGatewayFilter

    序 本文主要研究下spring cloud gateway的SecureHeadersGatewayFilter GatewayAutoConfiguration @Configuration @Co ...

  3. 聊聊spring cloud gateway的XForwardedHeadersFilter

    序 本文主要研究spring cloud gateway的XForwardedHeadersFilter GatewayAutoConfiguration spring-cloud-gateway-c ...

  4. 聊聊spring cloud gateway的SetStatusGatewayFilter

    序 本文主要研究下spring cloud gateway的SetStatusGatewayFilter GatewayAutoConfiguration spring-cloud-gateway-c ...

  5. 跟我学SpringCloud | 第十二篇:Spring Cloud Gateway初探

    SpringCloud系列教程 | 第十二篇:Spring Cloud Gateway初探 Springboot: 2.1.6.RELEASE SpringCloud: Greenwich.SR1 如 ...

  6. Spring Cloud Gateway 入门

    认识 Spring Cloud Gateway Spring Cloud Gateway 是一款基于 Spring 5,Project Reactor 以及 Spring Boot 2 构建的 API ...

  7. 网关Spring Cloud Gateway科普

    点击上方"朱小厮的博客",选择"设为星标" 后台回复"加群"获取公众号专属群聊入口 欢迎跳转到本文的原文链接:https://honeypp ...

  8. Spring Cloud Gateway CORS 方案看这篇就够了

    欢迎关注方志朋的博客,回复"666"获面试宝典 在 SpringCloud 项目中,前后端分离目前很常见,在调试时,会遇到两种情况的跨域: 前端页面通过不同域名或IP访问微服务的后 ...

  9. spring cloud gateway之filter篇

    点击上方"方志朋",选择"置顶或者星标" 你的关注意义重大! 在上一篇文章详细的介绍了Gateway的Predict,Predict决定了请求由哪一个路由处理, ...

最新文章

  1. 2022-2028年中国橡胶履带产业发展动态及投资趋势预测报告
  2. 用Transformer实现OCR字符识别!
  3. linux-xargs
  4. mysql错误1451_mysql错误代号-J(1451~1494)
  5. 第六章连接和分组查询
  6. 数据库索引优化原理,索引的工作机制
  7. 原来歌这样唱也很好听
  8. java斗地主怎么出牌_斗地主滑动选牌出牌(Cocos Creator)
  9. 如何才能快速匹配到大号?
  10. jmeter java性能_性能测试十一:jmeter进阶之java请求
  11. 如何配置Modbus读写器
  12. 数据结构与算法01:一张图概括【数据结构】是什么?(大白话+图解)
  13. 【MySQL】深入分析MySQL索引机制的实现
  14. 分析一种简单的提高功率因数的电路——填谷电路
  15. 微信企业号和企业微信消息发送区别
  16. 多元正态分布的极大似然估计
  17. cortex m3/m4处理器的复位设计
  18. 写GML到一个复杂的应用模式
  19. C#之:线程同步 Monitor类
  20. 作为一名程序员,如何利用自己的技术去创业和赚钱?

热门文章

  1. atitit.复合变量,也就是类似$$a的变量的原理与实现 java c#.net php js
  2. ns 25的IKE模式ipsec ***配置
  3. C#.Net 如何动态加载与卸载程序集(.dll或者.exe)6-----在不卸载程序域的前提下替换程序集文件。...
  4. 读书笔记:《HTML5开发手册》--figure、time、details、mark
  5. VBS学习日记(二) 基础知识
  6. windows上的svn服务器迁移到linux
  7. 如何向数据库添加时同时返回ID
  8. 是否会回到起点.回忆只能是回忆
  9. HTTP Header 详解,互联网营销
  10. 在Scrapy中使用Chrome中的cookie