Spring Cloud Gateway 过滤器执行顺序原理分析
过滤器类型GlobalFilter:全局过滤器,对所有路由生效。通过实现GlobalFilter接口创建GatewayFilter:网关过滤器,也可以说是局部过滤器、自定义过滤器,只对配置了此过滤器的路由生效。通过GatewayFilterFactory创建。过滤器会被执行两次,过滤分为pre和post。pre:请求前调用。post:响应结果返回时调用,顺序和pre完全相反,这里只讨论过滤器的pr
过滤器类型
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 {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("Ga 1");
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 1;
}
}
@Component
public class GbFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("Gb 2");
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 2;
}
}
@Component
public class GcFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("Gc 1");
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 1;
}
}
定义GatewayFilter过滤器
注意:这里为了简单,直接继承自AbstractNameValueGatewayFilterFactory,实际使用看自己需求选择继承类
@Component
public class FaGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
@Override
public GatewayFilter apply(NameValueConfig config) {
return (exchange, chain) -> {
System.out.println("Fa");
return chain.filter(exchange);
};
}
}
@Component
public class FbGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
@Override
public GatewayFilter apply(NameValueConfig config) {
return (exchange, chain) -> {
System.out.println("Fb");
return chain.filter(exchange);
};
}
}
@Component
public class FcGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
@Override
public GatewayFilter apply(NameValueConfig config) {
return (exchange, chain) -> {
System.out.println("Fc");
return chain.filter(exchange);
};
}
}
GatewayFilter类型的过滤器,只在配置了此过滤器的路由服务上生效,所以需要加到路由配置上,"="后面的n,v为NameValueConfig里面的值,这里随便写一下。
routes:
- id: 用户服务
uri: lb://user-service
predicates:
- 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<GatewayFilter> loadGatewayFilters(String id, List<FilterDefinition> filterDefinitions) {
List<GatewayFilter> 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<String, String> args = definition.getArgs();
if (this.logger.isDebugEnabled()) {
this.logger.debug("RouteDefinition " + id + " applying filter " + args + " to " + definition.getName());
}
Map<String, Object> 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<GatewayFilter> 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<Void> handle(ServerWebExchange exchange) {
Route route = (Route)exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
List<GatewayFilter> gatewayFilters = route.getFilters();
List<GatewayFilter> 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顺序,即为过滤器执行顺序。
更多推荐
所有评论(0)