过滤器的种类
Spring-Cloud-Gateway中提供了3种类型的过滤器,分别是:路由过滤器、Default过滤器和Global过滤器。
路由过滤器和Default过滤器
路由过滤器和Default过滤器本质上是同一种过滤器,只不过作用范围不一样,路由过滤器只针对单个路由起作用,而Default过滤器对整个路由表中所有的路由都起作用,这2个过滤器的处理逻辑都是Spring已经内置好的,无须开发人员来写代码,只需要做一下配置即可。
Spring已经提供好了30多种这样的过滤器,比如:
- AddRequestHeader
- AddRequestParameter
- StripPrefix
- …
这些过滤器都是org.springframework.cloud.gateway.filter.GatewayFilter
的子类,每一种过滤器都是由一种过滤器工厂来生成的,比如: - AddRequestHeaderGatewayFilterFactory生成AddRequestHeader的过滤器
- AddRequestParameterGatewayFilterFactory生成AddRequestParameter的过滤器
- StripPrefixGatewayFilterFactory生成StripPrefix的过滤器
Global过滤器
Global过滤器与上面两个不一样,Global过滤器需要开发人员自己来实现业务逻辑,并且它是org.springframework.cloud.gateway.filter.GlobalFilter
的子类。
过滤器的执行顺序
如果是Global过滤器,可以让Global过滤器实现org.springframework.core.Ordered
接口来设置过滤器的顺序,但是这里注意@org.springframework.core.annotation.Order
这个注解是不起作用的。
如果是路由过滤器和Default过滤器,他们的处理逻辑是Spring内置的,因此,他们的顺序是按照声明的顺序,从1开始递增的,比如:
routes:
- id: userservice
uri: lb://userservice
predicates:
- Path=/user/**
filters:
- AddRequestHeader=RouterFilter1, router1
- AddRequestHeader=RouterFilter2, router2
default-filters:
- AddRequestHeader=DefaultFilter1, default1
- AddRequestHeader=DefaultFilter1, default2
以上的配置种,router1的order是1,router2的order是2,default1的order是1,default2的order是2,也就是说按照他们声明的顺序,从1往上递增。
那么,当系统中同时存在这么多过滤器的时候,他们的执行顺序是什么样子的呢?比如,我现在同时定义了GlobalFilter1和GlobalFilter2,还有配置了router1、router2、default1、default2的时候:
@Component
public class GlobalFilter1 implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("============global1=============");
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 2;
}
}
还有GlobalFilter2:
@Component
public class GlobalFilter2 implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("============global2=============");
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 1;
}
}
只需要在org.springframework.cloud.gateway.handler.FilteringWebHandler#handle()
上打断点看一下即可:
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
// 拿到所有的路由过滤器,包含了Default过滤器
List<GatewayFilter> gatewayFilters = route.getFilters();
// 拿到所有的Global过滤器
List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
// 先添加的Global过滤器,然后再添加的路由过滤器
combined.addAll(gatewayFilters);
// TODO: needed or cached?
AnnotationAwareOrderComparator.sort(combined);
if (logger.isDebugEnabled()) {
logger.debug("Sorted gatewayFilterFactories: " + combined);
}
// 在这一行打断点,查看下combined之后的内容
return new DefaultGatewayFilterChain(combined).filter(exchange);
}
如下:
从源码种可以看出来,是先添加的Global过滤器,然后再添加的路由过滤器,从上面的截图也可以看出来,GlobalFilter2排在最前面,后面依次是default1、router1、GlobalFilter1、default2、router2。
可以继续在org.springframework.cloud.gateway.filter.factory.AddRequestHeaderGatewayFilterFactory#filter()
方法和GlobalFilter上打断点,看一下后续的执行顺序。
因此,这些过滤器的执行顺序首先是根据order进行的排序,如果order相同,优先级是Global>Default>Router。
3种过滤器的类型都不一样为啥可以在一块进行排序?
Global过滤器是org.springframework.cloud.gateway.filter.GlobalFilter
的子类,但是路由过滤器和Default过滤器是org.springframework.cloud.gateway.filter.GatewayFilter
的子类,他们为啥可以放在一个集合中进行排序呢?
还是看org.springframework.cloud.gateway.handler.FilteringWebHandler
这个类,它里面有一个loadFilters()
方法:
private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
return filters.stream().map(filter -> {
// 把GlobalFilter适配成了GatewayFilterAdapter
GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter);
// 并且这里计算顺序的时候,只是从Ordered接口取的
if (filter instanceof Ordered) {
int order = ((Ordered) filter).getOrder();
return new OrderedGatewayFilter(gatewayFilter, order);
}
return gatewayFilter;
}).collect(Collectors.toList());
}
// GatewayFilterAdapter 就实现了GatewayFilter接口
private static class GatewayFilterAdapter implements GatewayFilter {
private final GlobalFilter delegate;
GatewayFilterAdapter(GlobalFilter delegate) {
this.delegate = delegate;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return this.delegate.filter(exchange, chain);
}
}
从上面的源码可以看出来,gateway框架在启动的时候,会把系统中所有的GlobalFilter适配成GatewayFilterAdapter
,而GatewayFilterAdapter
是实现了GatewayFilter
接口的,因此GlobalFilter
也就适配成了GatewayFilter
,因此他们是可以放到一个集合进行排序的。同时可以看到,在获取GlobalFilter的order时候,只是使用Ordered
接口并没有使用@Order
注解。
结论
- Global过滤器的顺序是由
Ordered
接口来定义,@Order
不起作用。 - 路由过滤器和Default过滤器的顺序是按照声明的顺序,从1开始递增
- 所有的Global过滤器、路由过滤器、Default过滤器最终会放到一个集合中按照order大小进行排序
- 如果order值一样,优先就是Global过滤器>Default过滤器>路由过滤器
ps:以上测试结论基于<spring-cloud.version>Hoxton.SR10</spring-cloud.version>