hello云胜

技术与生活

0%

filter的执行顺序

路由的filter可以配置多个。

如果是GatewayFilter,根据其在路由中的配置确定其执行顺序

1
2
3
4
5
6
7
8
9
10
11
12
spring:
cloud:
gateway:
routes:
- id: path_route
uri: http://www.baidu.com
predicates:
- Path=/get
filters:
- AddRequestHeader=X-Request-Foo, Bar
- AddResponseHeader=X-Response-Foo, Bar
- DedupeResponseHeader=Foo

又因为一个请求分为进pre和出post两个方向。放在前面的filter在pre过程中先执行,在post过程中后执行。

Spring Cloud Gateway Diagram

然后再加上GlobalFilter,和GatewayFilter的顺序会怎么执行呢?

根据Ordered接口

我们自定义GlobalFilter时,都会同时实现Ordered接口。

他只有一个方法getOrder(),返回优先级。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Bean
public GlobalFilter customFilter() {
return new CustomGlobalFilter();
}

public class CustomGlobalFilter implements GlobalFilter, Ordered {

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("custom global filter");
return chain.filter(exchange);
}

@Override
public int getOrder() {
return -1;
}
}

数字越大,优先级越低,这个filter越靠后。

所以,源码中最高优先级的值就是Integer的最小值。

1
2
3
4
5
6
7
8
9
10
11
12

/**
* Useful constant for the highest precedence value.
* @see java.lang.Integer#MIN_VALUE
*/
int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;

/**
* Useful constant for the lowest precedence value.
* @see java.lang.Integer#MAX_VALUE
*/
int LOWEST_PRECEDENCE = Integer.MAX_VALUE;

做个测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@Slf4j
@Configuration
public class GatewayTest {
@Bean
@Order(-1)
public GlobalFilter a() {
return (exchange, chain) -> {
log.info("first pre filter");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("third post filter");
}));
};
}

@Bean
@Order(0)
public GlobalFilter b() {
return (exchange, chain) -> {
log.info("second pre filter");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("second post filter");
}));
};
}

@Bean
@Order(1)
public GlobalFilter c() {
return (exchange, chain) -> {
log.info("third pre filter");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("first post filter");
}));
};
}
}

触发一个请求,打印日志

1
2
3
4
5
6
7
first pre filter
second pre filter
third pre filter

first post filter
second post filter
third post filter

也可以看出,“pre”类型的过滤器是在(exchanges,chain)->{}中执行的,

而“post”类型的过滤器是在chain.filter(exchange).then(Mono.fromRunnable(()->{}))中执行的。

以上代码,如果不喜欢lambda形式的写法,等价于以下写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Slf4j
@Component
public class CorsResponseHeaderFilter implements GlobalFilter, Ordered {

@Override
public int getOrder() {
return 1;
}

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("third pre filter");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("first post filter");
}));
}