Spring Cloud Gateway 过滤器执行顺序原理分析

过滤器类型

GlobalFilter:全局过滤器,对所有路由生效。通过实现GlobalFilter接口创建

GatewayFilter:网关过滤器,也可以说是局部过滤器、自定义过滤器,只对配置了此过滤器的路由生效。通过GatewayFilterFactory创建

过滤器会被执行两次,过滤分为pre和post。

pre:请求前调用。

post:响应结果返回时调用,顺序和pre完全相反,这里只讨论过滤器的pre执行顺序,post倒置过来就行了。

先说结论

结论

网上的说法都不太准确,其实并没有多花里胡哨的。

最终都是通过Order值进行排序执行,Order值越小越先执行。

源码在org.springframework.cloud.gateway.handler.FilteringWebHandler#handle方法里面

AnnotationAwareOrderComparator.sort(combined);

至于为什么会出现一些莫名其妙的排序情况,都是Order值相同或者不理解Order值生成规则照成的。下面先解释这两点,最后会通过代码验证,源码分析加以说明。

Order值相同时

1.两个GlobalFilter类型的过滤器Order值相同时,根据文件名字母排序,文件名靠前的优先更高。

原因是包扫描时是按照文件的顺序扫描的,然后封装到List集合的,通过Order值排序时如果Order值相同,文件名在前名的依然会排在前面。

2.GlobalFilter类型和GatewayFilter类型的过滤器Order值相同时,GlobalFilter类型优先更高。

原因是这两种过滤器最终会合并到一个过滤器集合中形成过滤器调用链,源码是通过list.addAll();方法将GatewayFilter类型的过滤器加到了GlobalFilter过滤器集合中,addAll()是末尾添加方式,所以Order值相同时GatewayFilter类型的过滤器会排在后面。

Order值生成规则

1.GlobalFilter类型过滤器,通过实现Ordered接口的getOrder()方法设置。

2.GatewayFilter类型过滤器,无法手动设置Order值,通过配置文件中配置的过滤器顺序自动生成,固定从1开始封装,例如配置了三个过滤器,则按照从上往下顺序Order值依次为1、2、3。

补充说明:GatewayFilter也可以自定义顺序,详见:Spring Cloud Gateway GatewayFilter自定义过滤器顺序_xzh_blog-CSDN博客

代码验证

定义GlobalFilter过滤器

@Component
public class GaFilter implements GlobalFilter, Ordered {@Overridepublic Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {System.out.println("Ga 1");return chain.filter(exchange);}@Overridepublic int getOrder() {return 1;}
}
@Component
public class GbFilter implements GlobalFilter, Ordered {@Overridepublic Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {System.out.println("Gb 2");return chain.filter(exchange);}@Overridepublic int getOrder() {return 2;}
}
@Component
public class GcFilter implements GlobalFilter, Ordered {@Overridepublic Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {System.out.println("Gc 1");return chain.filter(exchange);}@Overridepublic int getOrder() {return 1;}
}

定义GatewayFilter过滤器

注意:这里为了简单,直接继承自AbstractNameValueGatewayFilterFactory,实际使用看自己需求选择继承类

@Component
public class FaGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {@Overridepublic GatewayFilter apply(NameValueConfig config) {return (exchange, chain) -> {System.out.println("Fa");return chain.filter(exchange);};}
}
@Component
public class FbGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {@Overridepublic GatewayFilter apply(NameValueConfig config) {return (exchange, chain) -> {System.out.println("Fb");return chain.filter(exchange);};}
}
@Component
public class FcGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {@Overridepublic GatewayFilter apply(NameValueConfig config) {return (exchange, chain) -> {System.out.println("Fc");return chain.filter(exchange);};}
}

GatewayFilter类型的过滤器,只在配置了此过滤器的路由服务上生效,所以需要加到路由配置上,"="后面的n,v为NameValueConfig里面的值,这里随便写一下。

      routes:- id: 用户服务uri: lb://user-servicepredicates:- Path=/user-service/**filters:- Fa=n, v- Fc=n, v- Fb=n, v

结果输出

Ga 1
Gc 1
Fa
Gb 2
Fc
Fb

源码分析

服务启动时,org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator会将路由中配置了的过滤器加载到路由的过滤器集合中,并封装Order值。

    private List loadGatewayFilters(String id, List filterDefinitions) {List filters = (List)filterDefinitions.stream().map((definition) -> {// 从过滤器工厂中取出配置了的过滤器封装到路由的过滤器集合中GatewayFilterFactory factory = (GatewayFilterFactory)this.gatewayFilterFactories.get(definition.getName());if (factory == null) {throw new IllegalArgumentException("Unable to find GatewayFilterFactory with name " + definition.getName());} else {Map args = definition.getArgs();if (this.logger.isDebugEnabled()) {this.logger.debug("RouteDefinition " + id + " applying filter " + args + " to " + definition.getName());}Map properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory);Object configuration = factory.newConfig();ConfigurationUtils.bind(configuration, properties, factory.shortcutFieldPrefix(), definition.getName(), this.validator);GatewayFilter gatewayFilter = factory.apply(configuration);if (this.publisher != null) {this.publisher.publishEvent(new FilterArgsEvent(this, id, properties));}return gatewayFilter;}}).collect(Collectors.toList());ArrayList ordered = new ArrayList(filters.size());// 遍历过滤器集合,封装成带Order值的过滤器集合for(int i = 0; i < filters.size(); ++i) {GatewayFilter gatewayFilter = (GatewayFilter)filters.get(i);if (gatewayFilter instanceof Ordered) {ordered.add(gatewayFilter);} else {// 从1开始递增生成Order值ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));}}return ordered;}

请求网关时,org.springframework.cloud.gateway.handler.FilteringWebHandler会将路由中的过滤器和全局过滤器合并封装排序,生成完整的过滤器链。

    public Mono handle(ServerWebExchange exchange) {Route route = (Route)exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);List gatewayFilters = route.getFilters();List combined = new ArrayList(this.globalFilters);// 将路由中的过滤器集合添加到全局过滤器集合combined.addAll(gatewayFilters);// 排序算法AnnotationAwareOrderComparator.sort(combined);if (logger.isDebugEnabled()) {logger.debug("Sorted gatewayFilterFactories: " + combined);}return (new FilteringWebHandler.DefaultGatewayFilterChain(combined)).filter(exchange);}

debug调试

通过debug调试,排序前的过滤器顺序,可以看出路由中配置的GatewayFilter类型过滤器是追加在GlobalFilter过滤器集合后面,并且可以看出GatewayFilter类型的过滤器Order值是1、2、3。

排序后,按照Order值排序,GlobalFilter类型过滤器的Order值相同时,按文件名排序,GatewayFilte和GlobalFilterr类型过滤器的Order值相同时也是排在GlobalFilter下面。

 

所以最终的执行顺序是

 

 可以自己在项目中debug调试,查看org.springframework.cloud.gateway.handler.FilteringWebHandler#handle中的combined顺序,即为过滤器执行顺序。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部