本文基于Spring Cloud Gateway 2.1.1.RELEASE。html
在讲SCG的Filter的排序问题以前得先比较一下Spring Cloud Gateway在对待Filter的方面与Zuul2有着哪些不一样。java
SCG所谓Route Filter就是像下面这样的:git
spring: cloud: gateway: routes: - id: tomcat_route uri: http://tomcat:8080 predicates: - Path=/tomcat/docs filters: - StripPrefix=1 - RemoveRequestHeader=X-Request-Foo
上面的StripPrefix
和RemoveRequestHeader
就是Route Filter,而SCG的Global Filter则是隐式的,无需显式配置,它们会在请求过来的时候被SCG调用。github
也就是说你能够配置不一样的Route,而后为每一个Route配置不一样的Route Filter,这一切都是在配置阶段就决定下来的。spring
而Zuul2则都是Global Filter,所以你得运行时在每一个Filter内部本身决定是否要干活,除此以外,发送到Origin(被代理的服务)的url也得你本身设置,下面是一个例子(来自Zuul2 Sample):api
public class Routes extends HttpInboundSyncFilter { @Override public boolean shouldFilter(HttpRequestMessage httpRequestMessage) { // ... return true; } @Override public HttpRequestMessage apply(HttpRequestMessage request) { // ... // Route healthchecks to the healthcheck endpoint.; context.setEndpoint(ZuulEndPointRunner.PROXY_ENDPOINT_FILTER_NAME); context.setRouteVIP("tomcat"); return request; } }
下面是SCG的Pre Filter(裁剪自官方例子12.2 Writing Custom GatewayFilter Factories):tomcat
public class PreGatewayFilterFactory extends AbstractGatewayFilterFactory { @Override public GatewayFilter apply(Config config) { return (exchange, chain) -> { // business logic return chain.filter(); }; } }
Post Filter的例子:app
public class PostGatewayFilterFactory extends AbstractGatewayFilterFactory { @Override public GatewayFilter apply(Config config) { return (exchange, chain) -> { return chain.filter(exchange).then(/* business logic */); }; } }
在Zuul2里,你则得分别实现HttpInboundSyncFilter
和HttpOutboundSyncFilter
,ProxyEndpoint
不须要你本身实现。ide
SCG的优势很明显,它作了Zuul2不作的事情:post
可是随着对SCG的深刻了解,发现了关于Filter的执行顺序存在一些坑,若是不了解清楚会容易出错。
前面讲了,SCG在执行过程当中Global Filter和Route Filter是一块儿执行的,那么它们的order是怎样的?
先来看看Global Filter,你能够访问/actuator/gateway/globalfilters
(见文档)获得Global Filter的排序:
那么若是你写了一个自定义 Global Filter,那么它的order是什么呢?这个要看状况:
Ordered
接口或者写了@Order
注解,那么它的order就是它本身设定的值关于这点能够看FilteringWebHandler.java的源代码。
再来看看Route Filter,这也分两种状况:
Ordered
接口或者写了@Order
注解,那么它的order就是它本身设定的值。关于这点能够看RouteDefinitionRouteLocator.java的源代码。
最后SCG把它们两个结合起来,作一个排序,对于没有order的Filter,它的order则默认为Ordered.LOWEST_PRECEDENCE
。关于这点能够看FilteringWebHandler.java的源代码。
用一张图作总结:
先看SCG文档3. How It Works中的这张图:
这张图大概告诉你了SCG的调用过程,能够看到通过了一堆Filters,可是并无告诉你Filter的执行顺序。而后在SCG的6.1 Combined Global Filter and GatewayFilter Ordering提到了:
As Spring Cloud Gateway distinguishes between "pre" and "post" phases for filter logic execution (see: How It Works), the filter with the highest precedence will be the first in the "pre"-phase and the last in the "post"-phase.
也就是说意思若是这个Filter是Pre Filter,那么执行顺序和排序顺序相同,若是这个Filter是Post Filter则执行顺序和排序顺序相反。我整理了一下SCG自带GlobalFilter的执行顺序:
能够看到GatewayMetricsFilter既是Pre Filter也是Post Filter。
执行某个Route的时候,SCG会将Global Filter和Route Filter结合起来并排序:
若是你要自定义Global Filter,那么通常来讲:
若是你要自定义Route Filter,那么通常来讲:
ForwardPathFilter
和RouteToRequestUrlFilter
之间,并且不须要实现Ordered
接口或添加@Order
注解