SpringCloud-Gateway过滤器源码分析

Spring-Cloud-Gateway的过滤器接口分为两种:

  1. GlobalFilter : 全局过滤器,不需要在配置文件中配置,作用在所有的路由上,最终通过GatewayFilterAdapter包装成GatewayFilterChain可识别的过滤器
  2. GatewayFilter : 需要通过spring.cloud.routes.filters 配置在具体路由下,只作用在当前路由上或通过spring.cloud.default-filters配置在全局,作用在所有路由上

在Spring-Cloud-Gateway之请求处理流程文中我们了解最终网关是将请求交给过滤器链表进行处理,接下来我们阅读Spring-Cloud-Gateway的整个过滤器类结构以及主要功能


通过源码可以看到Spring-Cloud-Gateway的filter包中接口有如下三个,GatewayFilter,GlobalFilter,GatewayFilterChain,下来我依次阅读接口的主要实现功能。

1. GatewayFilterChain

1
2
3
4
5
6
/**
* 网关过滤链表接口
* 用于过滤器的链式调用
*/
public interface GatewayFilterChain {
Mono<Void> filter(ServerWebExchange exchange);
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/**
* 网关过滤的链表,用于过滤器的链式调用
* 过滤器链表接口的默认实现,
* 包含2个构建函数:
* 1.集合参数构建用于初始化吧构建链表
* 2. index,parent参数用于构建当前执行过滤对应的下次执行的链表
*/
private static class DefaultGatewayFilterChain implements GatewayFilterChain {

/**
* 当前过滤执行过滤器在集合中索引
*/
private final int index;
/**
* 过滤器集合
*/
private final List<GatewayFilter> filters;

public DefaultGatewayFilterChain(List<GatewayFilter> filters) {
this.filters = filters;
this.index = 0;
}

/**
* 构建
* @param parent 上一个执行过滤器对应的FilterChain
* @param index 当前要执行过滤器的索引
*/
private DefaultGatewayFilterChain(DefaultGatewayFilterChain parent, int index) {
this.filters = parent.getFilters();
this.index = index;
}

public List<GatewayFilter> getFilters() {
return filters;
}

/**
* @param exchange the current server exchange
* @return
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange) {
return Mono.defer(() -> {
if (this.index < filters.size()) {
//获取当前索引的过滤器
GatewayFilter filter = filters.get(this.index);
//构建当前索引的下一个过滤器的FilterChain
DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this, this.index + 1);
//调用过滤器的filter方法执行过滤器
return filter.filter(exchange, chain);
} else {
//当前索引大于等于过滤集合大小,标识所有链表都已执行完毕,返回空
return Mono.empty(); // complete
}
});
}
}

过滤器的GatewayFilterChain 执行顺序

  1. 通过GatewayFilter集合构建顶层的GatewayFilterChain
  2. 调用顶层GatewayFilterChain,获取第一个Filter,并创建下一个Filter索引对应的GatewayFilterChain
  3. 调用filter的filter方法执行当前filter,并将下次要执行的filter对应GatewayFilterChain传入。

2. GatewayFilter

1
2
3
4
5
6
7
8
//网关路由过滤器
public interface GatewayFilter extends ShortcutConfigurable {

String NAME_KEY = "name";
String VALUE_KEY = "value";
Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);

}

网关过滤器接口,有且只有一个方法filter,执行当前过滤器,并在此方法中决定过滤器链表是否继续往下执行,接下来我们看下几个主要的功能实现类

2.1 OrderedGatewayFilter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 排序的网关路由过滤器,用于包装真实的网关过滤器,已达到过滤器可排序
*/
public class OrderedGatewayFilter implements GatewayFilter, Ordered {
//目标过滤器
private final GatewayFilter delegate;
//排序字段
private final int order;

public OrderedGatewayFilter(GatewayFilter delegate, int order) {
this.delegate = delegate;
this.order = order;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return this.delegate.filter(exchange, chain);
}
}

OrderedGatewayFilter实现类主要目的是为了将目标过滤器包装成可排序的对象类型。是目标过滤器的包装类

2.2 GatewayFilterAdapter
1
2
3
4
5
6
7
8
9
10
11
12
//全局过滤器的包装类,将全局路由包装成统一的网关过滤器
private static class GatewayFilterAdapter implements GatewayFilter {
//全局过滤器
private final GlobalFilter delegate;
public GatewayFilterAdapter(GlobalFilter delegate) {
this.delegate = delegate;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return this.delegate.filter(exchange, chain);
}
}

GatewayFilterAdapter实现类主要目的是为了将GlobalFilter过滤器包装成GatewayFilter类型的对应。是GlobalFilter过滤器的包装类

3. GlobalFilter

GlobalFilter 为请求业务以及路由的URI转换为真实业务服务的请求地址的核心过滤器,不需要配置,模式系统初始化时加载,并作用在每个路由上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//GatewayAutoConfiguration 类
// 全局过滤器,用户通过HttpClient转发请求
@Bean
public NettyRoutingFilter routingFilter(HttpClient httpClient,
ObjectProvider<List<HttpHeadersFilter>> headersFilters) {
return new NettyRoutingFilter(httpClient, headersFilters);
}
// 全局的过滤器,用户将HttpClient客户端转发请求的响应写入到原始的请求响应中
@Bean
public NettyWriteResponseFilter nettyWriteResponseFilter(GatewayProperties properties) {
return new NettyWriteResponseFilter(properties.getStreamingMediaTypes());
}

//GatewayLoadBalancerClientAutoConfiguration 类
// 全局过滤器,用于在通过负载均衡客户端选择服务实例信息
@Bean
@ConditionalOnBean(LoadBalancerClient.class)
public LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient client) {
return new LoadBalancerClientFilter(client);
}

GlobalFilter转换成GatewayFilter,并作用于每个路由上,在FilteringWebHandler实现

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
37
38
39
40
41
42
//FilteringWebHandler类
public class FilteringWebHandler implements WebHandler {
//存放适配后的全局过滤器
private final List<GatewayFilter> globalFilters;
public FilteringWebHandler(List<GlobalFilter> globalFilters) {
this.globalFilters = loadFilters(globalFilters);
}
//包装加载全局的过滤器,将全局过滤器包装成GatewayFilter
private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
return filters.stream()
.map(filter -> {
//将所有的全局过滤器包装成网关过滤器
GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter);
//判断全局过滤器是否实现了可排序接口
if (filter instanceof Ordered) {
int order = ((Ordered) filter).getOrder();
//包装成可排序的网关过滤器
return new OrderedGatewayFilter(gatewayFilter, order);
}
return gatewayFilter;
}).collect(Collectors.toList());
}
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
//获取请求上下文设置的路由实例
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
//获取路由定义下的网关过滤器集合
List<GatewayFilter> gatewayFilters = route.g1etFilters();

//组合全局的过滤器与路由配置的过滤器
List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
//添加路由配置过滤器到集合尾部
combined.addAll(gatewayFilters);
//对过滤器进行排序
//TODO: needed or cached?
AnnotationAwareOrderComparator.sort(combined);

logger.debug("Sorted gatewayFilterFactories: "+ combined);
//创建过滤器链表对其进行链式调用
return new DefaultGatewayFilterChain(combined).filter(exchange);
}
}
  1. loadFilters方法是将全局路由使用GatewayFilterAdapter包装成GatewayFilter
  2. handle方法
    • 获取当前请求使用的路由Route
    • 获取路由配置的过滤器集合route.getFilters()
    • 合并全过滤器与路由配置过滤器combined
    • 对过滤器排序AnnotationAwareOrderComparator.sort
    • 通过过滤器集合构建顶级链表DefaultGatewayFilterChain,并对其当前请求调用链表的filter方法。

4. 过滤器是怎么调用的

FilteringWebHandler在自动配置类中注入容器:

1
2
3
4
5
//GatewayAutoConfiguration
@Bean
public FilteringWebHandler filteringWebHandler(List<GlobalFilter> globalFilters) {
return new FilteringWebHandler(globalFilters);
}

带参数的注入方法:默认情况下spring会在容器中找到所有的GlobalFilter,构建成list作为参数

FilteringWebHandler是实现了WebHandler,说明这是一个处理请求的处理器

FilteringWebHandler是怎么被调用到用来处理请求的呢?

那就要从RoutePredicateHandlerMapping开始分析,我们知道spring mvc中的HandlerMapping的作用主要就是通过请求的路径map到处理该请求的controller方法(也就是handler),而在spring gateway中,RoutePredicateHandlerMapping的作用就是使用请求的各种属性,通过pridicate,map到一个路由配置上去。

RoutePredicateHandlerMapping持有FilteringWebHandler类,也就持有了所有的请求过滤器(全局+路由配置下的GatewayFilter),

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
37
public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {

private final FilteringWebHandler webHandler;

private final RouteLocator routeLocator;
private final Integer managementPort;
private final ManagementPortType managementPortType;

@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
// don't handle requests on management port if set and different than server port
if (this.managementPortType == DIFFERENT && this.managementPort != null
&& exchange.getRequest().getURI().getPort() == this.managementPort) {
return Mono.empty();
}
exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());

return lookupRoute(exchange)
// .log("route-predicate-handler-mapping", Level.FINER) //name this
.flatMap((Function<Route, Mono<?>>) r -> {
exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
if (logger.isDebugEnabled()) {
logger.debug(
"Mapping [" + getExchangeDesc(exchange) + "] to " + r);
}

exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
return Mono.just(webHandler);
}).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
if (logger.isTraceEnabled()) {
logger.trace("No RouteDefinition found for ["
+ getExchangeDesc(exchange) + "]");
}
})));
}
}

看上面源码,RouteLocator从名字就能大概猜到这是一个路由定位器,负责寻找正确的路由配置。

方法getHandlerInternal,顾名思义在内部获取handler处理器