Spring-Cloud-Gateway的过滤器的执行顺序问题

过滤器的种类

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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值