1. 上回书传送门:2. 概述
在上一篇,我们分析了spring-cloud-gateway请求路由过程的前两步:

我们知道第二步拿到的Handler,实际上是第一步匹配到的RoutePredicateHandlerMapping所持有的FilteringWebHandler对象。而它的本职工作是将GlobalFilter(全局过滤器)、GatewayFilter(一般来说是我们自己配置的,当然也默认内置了一些),放到同一个List里进行优先级排序PHP过滤器,生成一个过滤器链。执行过滤器链,就能顺序执行链中保存的所有Filter。
3. 源码分析3.1 初始化时加载所有全局过滤器
public class FilteringWebHandler implements WebHandler {
// 所有全局过滤器
private final List<GatewayFilter> globalFilters;
public FilteringWebHandler(List<GlobalFilter> globalFilters) {
// 1.初始化时加载所有全局过滤器,将他们适配为GatewayFilter类型,方便等会做合并
this.globalFilters = loadFilters(globalFilters);
}
// 适配器模式,通过两次套娃把GlobalFilter封装成GatewayFilter类型
private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
return filters.stream().map(filter -> {
// 2.Adapter持有GlobalFilter的引用
GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter);
if (filter instanceof Ordered) {
int order = ((Ordered) filter).getOrder();
// 3.OrderedGatewayFilter再持有一个Adapter
// 其实这里搞的挺无语的,那我直接返回Adapter又不是不能用,毕竟接口相同
// 说白了,还是跟职责隔离、设计解耦有关
// 就好比有时我们会纠结干嘛不直接把路由配置读成Route是类似的
// 因为我们的思维模式,就是快点达到目的,而忽略了扩展性
// 假设现在我们需要有一个服务提供多个接口,包括了Filter接口的功能
// 那么,我们还是直接在Adapter上加接口,再持有一个跟它功能无关的工具人干活?
// 那职责就完全乱套了,我们大可以这样:
// Kunkun implements ISing,IJump,IRap,IBasketball {
// private ISing singAdapter;
// private IJump jumpAdapter;
// private IRap rapAdapter;
// private IBasketball basketballAdapter;
// }
// 那么坤坤就会唱、跳、rap、篮球了
return new OrderedGatewayFilter(gatewayFilter, order);
}
return gatewayFilter;
}).collect(Collectors.toList());
}
GatewayFilterAdapter源码片段:
/**
* GatewayFilter的适配器模式,将filter()操作委托给持有的GlobalFilter实例去执行
* 这样就可以把GlobalFilter伪装成GatewayFilter来用
*/
private static class GatewayFilterAdapter implements GatewayFilter {
// 真正干活的
private final GlobalFilter delegate;
}
OrderedGatewayFilter代码片段:
public class OrderedGatewayFilter implements GatewayFilter, Ordered {
// 这里实际就是塞的GatewayFilterAdapter,老套娃了
private final GatewayFilter delegate;
}
3.2 合并GlobalFilter和GatewayFilter
public Mono<Void> handle(ServerWebExchange exchange) {
// 1.从exchange里拿到第二步匹配好的Route(匹配到后塞进去的)
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
// 2.通过这个Route拿到它对应的GatewayFilter列表
List<GatewayFilter> gatewayFilters = route.getFilters();
// 3.把前面已经适配为GatewayFilter的全局过滤器拿过来,初始化一个总的过滤器列表
List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
// 4.然后把从Route里拿到的过滤器列表也塞进去合并
combined.addAll(gatewayFilters);
// 5.对总的过滤器列表按优先级排序
AnnotationAwareOrderComparator.sort(combined);
// 6.通过这个总的过滤器列表构造一个过滤器链来执行过滤逻辑
return new DefaultGatewayFilterChain(combined).filter(exchange);
}
3.3 生成过滤器链DefaultGatewayFilterChain
/**
* 默认的过滤器链实现,其实把叫DefaultGatewayFilterChainElement会更好理解一些。
* 假设我们把一个DefaultGatewayFilterChain的实例称为 chainElement,那么整个
* 过滤器链实际上是 chainElement -> chainElement -> chainElement的逻辑结构
*/
private static class DefaultGatewayFilterChain implements GatewayFilterChain {
// 记录当前这个Chain实例对应要执行的filter位置
private final int index;
// 所有要执行的filter列表
private final List<GatewayFilter> filters;
/**
* 当我们最开始用一组 filter去初始化得到一个 ChainElement
* 此时 chainElement的index记录了它所对应的filter为第一个(index=0)
* 那么我们执行 chainElement.filter()实际执行的是filter_0.filter()
* 它里面又会返回ChainElement.filter()方法的调用,宁看我,那我也看宁。
* 于是变成这样蛋疼无比的循环:
* chainElement0.filter()
* -> new ChainElement() chainElement1; ChainElement0.filter.filter(chainElement1);
* -> newChainElement1.filter()
* -> new ChainElement() chainElement2; ChainElement1.filter.filter(chainElement2);
* -> newChainElement2.filter()
* -> ...
* 每次执行ChainElement.filter()都会构造新的newChainElement
* 然后执行自己对应的filter的filter()
* 最后newChainElement.filter()
* 就这样不停循环到所有filter都被执行了才停止构造ChainElement,
* 返回Mono.empty(),实际上把他想成一个void方法的调用就行了
*/
DefaultGatewayFilterChain(List<GatewayFilter> filters) {
this.filters = filters;
this.index = 0;
}
// 通过一个parentChain构造一个新Chain
// 其实在调用处index=parent.index+1,让它指向下一个filter
private DefaultGatewayFilterChain(DefaultGatewayFilterChain parent, int index) {
this.filters = parent.getFilters();
this.index = index;
}
public List<GatewayFilter> getFilters() {
return filters;
}
// 每个Chain的执行方法
@Override
public Mono<Void> filter(ServerWebExchange exchange) {
return Mono.defer(() -> {
// index没超出filters的下标范围,就说明还有filter可以执行
if (this.index < filters.size()) {
// 先通过index拿到当前Chain需要执行的filter
GatewayFilter filter = filters.get(this.index);
// 然后构造下一个Chain,让它index+1指向下一个filter
DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this,
this.index + 1);
// 最终还是执行的filter自己的过滤方法,然后开始了套娃
return filter.filter(exchange, chain);
}
// index >= filers.size()时,说明所有的filter都执行完了,直接返回Mono.empty()
else {
return Mono.empty(); // complete
}
});
}
}
4. 小结
本篇我们分析了FilteringWebHandler创建和执行过滤器链的流程。由于这种责任链模式写法比较少见,可以把DefaultGatewayFilterChain想象成一个个ChainElement来辅助理解,多看多调试,慢慢就搞懂啦~感谢观看~
5. 下回书已更新
(编辑:威海站长网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|