Spring Cloud Gateway 过滤器执行顺序原理分析

public int getOrder() {

return 1;

}

}

定义GatewayFilter过滤器

注意:这里为了简单,直接继承自AbstractNameValueGatewayFilterFactory,实际使用看自己需求选择继承类

@Component

public class FaGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {

@Override

public GatewayFilter apply(NameValueConfig config) {

return (exchange, chain) -> {

System.out.println(“Fa”);

return chain.filter(exchange);

};

}

}

@Component

public class FbGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {

@Override

public GatewayFilter apply(NameValueConfig config) {

return (exchange, chain) -> {

System.out.println(“Fb”);

return chain.filter(exchange);

};

}

}

@Component

public class FcGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {

@Override

public GatewayFilter apply(NameValueConfig config) {

return (exchange, chain) -> {

System.out.println(“Fc”);

return chain.filter(exchange);

};

}

}

GatewayFilter类型的过滤器,只在配置了此过滤器的路由服务上生效,所以需要加到路由配置上,"="后面的n,v为NameValueConfig里面的值,这里随便写一下。

routes:

  • id: 用户服务

uri: lb://user-service

predicates:

  • Path=/user-service/**

filters:

  • Fa=n, v

  • Fc=n, v

  • Fb=n, v

结果输出

Ga 1

Gc 1

Fa

Gb 2

Fc

Fb

源码分析


服务启动时,org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator会将路由中配置了的过滤器加载到路由的过滤器集合中,并封装Order值。

private List loadGatewayFilters(String id, List filterDefinitions) {

List filters = (List)filterDefinitions.stream().map((definition) -> {

// 从过滤器工厂中取出配置了的过滤器封装到路由的过滤器集合中

GatewayFilterFactory factory = (GatewayFilterFactory)this.gatewayFilterFactories.get(definition.getName());

if (factory == null) {

throw new IllegalArgumentException("Unable to find GatewayFilterFactory with name " + definition.getName());

} else {

Map<String, String> args = definition.getArgs();

if (this.logger.isDebugEnabled()) {

this.logger.debug("RouteDefinition " + id + " applying filter " + args + " to " + definition.getName());

}

Map<String, Object> properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory);

Object configuration = factory.newConfig();

ConfigurationUtils.bind(configuration, properties, factory.shortcutFieldPrefix(), definition.getName(), this.validator);

GatewayFilter gatewayFilter = factory.apply(configuration);

if (this.publisher != null) {

this.publisher.publishEvent(new FilterArgsEvent(this, id, properties));

}

return gatewayFilter;

}

}).collect(Collectors.toList());

ArrayList ordered = new ArrayList(filters.size());

// 遍历过滤器集合,封装成带Order值的过滤器集合

for(int i = 0; i < filters.size(); ++i) {

GatewayFilter gatewayFilter = (GatewayFilter)filters.get(i);

if (gatewayFilter instanceof Ordered) {

ordered.add(gatewayFilter);

} else {

// 从1开始递增生成Order值

ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));

}

}

return ordered;

}

请求网关时,org.springframework.cloud.gateway.handler.FilteringWebHandler会将路由中的过滤器和全局过滤器合并封装排序,生成完整的过滤器链。

public Mono handle(ServerWebExchange exchange) {

Route route = (Route)exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);

List gatewayFilters = route.getFilters();

List combined = new ArrayList(this.globalFilters);

// 将路由中的过滤器集合添加到全局过滤器集合

combined.addAll(gatewayFilters);

// 排序算法

AnnotationAwareOrderComparator.sort(combined);

if (logger.isDebugEnabled()) {

logger.debug("Sorted gatewayFilterFactories: " + combined);

}

return (new FilteringWebHandler.DefaultGatewayFilterChain(combined)).filter(exchange);

}

debug调试


通过debug调试,排序前的过滤器顺序,可以看出路由中配置的GatewayFilter类型过滤器是追加在GlobalFilter过滤器集合后面,并且可以看出GatewayFilter类型的过滤器Order值是1、2、3。

排序后,按照Order值排序,GlobalFilter类型过滤器的Order值相同时,按文件名排序,GatewayFilte和GlobalFilterr类型过滤器的Order值相同时也是排在GlobalFilter下面。

技术学习总结

学习技术一定要制定一个明确的学习路线,这样才能高效的学习,不必要做无效功,既浪费时间又得不到什么效率,大家不妨按照我这份路线来学习。

最后面试分享

大家不妨直接在牛客和力扣上多刷题,同时,我也拿了一些面试题跟大家分享,也是从一些大佬那里获得的,大家不妨多刷刷题,为金九银十冲一波!

路线来学习。

[外链图片转存中…(img-9bqxHCGH-1714453793824)]

[外链图片转存中…(img-Y5KxMn60-1714453793825)]

[外链图片转存中…(img-AeARCg5s-1714453793825)]

最后面试分享

大家不妨直接在牛客和力扣上多刷题,同时,我也拿了一些面试题跟大家分享,也是从一些大佬那里获得的,大家不妨多刷刷题,为金九银十冲一波!

[外链图片转存中…(img-renRs7H7-1714453793825)]

[外链图片转存中…(img-ZK3V141T-1714453793826)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 21
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值