本文基於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
註解