Soul网关源码学习(10)- 插件模板 AbstractSoulPlugin

前言

在前一篇文章《Soul网关源码学习(9)- 请求解析 GlobalPlugin》 中,我们学习请求流入的第一个插件 GlobalPlugin 的源码,GlobalPlugin 处理完之后,请求就有可能因为协议的不同而流向不同的插件路线,而后面这些插件的实现有很大一部分都有着一个共同的抽象模板 AbstractSoulPlugin,所以在学习后面这些插件的源码之前,有必要先来了解一下 AbstractSoulPlugin 的实现。

AbstractSoulPlugin

AbstractSoulPlugin 顾名思义,是一个抽象模板类,SoulPlugin 的大部分实现都继承于它。它实现了 SoulPlugin#execute(ServerWebExchange, SoulPluginChain) 接口方法,提供了一些数据预处理的模板流程,并将真正的执行逻辑委派给子类的 doExecute(ServerWebExchange, SoulPluginChain, SelectorData, RuleData) 方法。

//下面代码,省略了具体的处理,只列出流程的关键节点
@Override
public Mono<Void> execute(final ServerWebExchange exchange, final SoulPluginChain chain) {
    
    
    String pluginName = named();
    final PluginData pluginData = BaseDataCache.getInstance().obtainPluginData(pluginName);
    // 处理插件数据
    if (pluginData != null && pluginData.getEnabled()) {
    
    
    	//处理选择器 selector 数据
        final Collection<SelectorData> selectors = BaseDataCache.getInstance().obtainSelectorData(pluginName);
        selectorLog(selectorData, pluginName);
        ...
        //处理接口规则 rule
        final List<RuleData> rules = BaseDataCache.getInstance().obtainRuleData(selectorData.getId());
        ...
        //子类执行真正的处理逻辑
        return doExecute(exchange, chain, selectorData, rule);
    }
    //间接递归 插件链的 execute 方法
    return chain.execute(exchange);
}

从上面的代码中我们能梳理出代码流程中的几个主要节点,也是我们今天分析的要点:

  • 获取插件数据 pluginData,判断其是否可用(加载 + 打开状态)。
  • 获取 SelectorData 并且处理。
  • 获取 Rule 集合并且处理。
  • 委派子类方法 doExecute 执行真正的处理逻辑。

pluginData

PluginData 是描述插件的一些基本数据信息,在 soul admin 中的体现:

在这里插入图片描述
PluginData 会通过数据同步机制,从 soul admin 同步到网关本地内存中,因为网关获取到的数据都是本地缓存的副本。对于这一点,soul 网关所有配置信息都是一样的,也包括后面的 selectorData 和 Rule。

模板方法首先判断 PluginData 是否为空,为空则表示插件则没被加载,也就是没有添加相应的插件依赖;否则,再判断其是否打开,也就是上面图片中的 Status 是否处于 open 状态。如果两个条件满足了,才会往下执行,否则就结束当前插件处理,跳回插件链。

SelectorData

官方文档说法:选择器和规则是soul网关中最灵魂的东西。掌握好它,你可以对任何流量进行管理。

不过在AbstractSoulPlugin中并不涉及数据的使用,而只是实现对 SelectorData 的获取和筛选,真正的处理是交由子类方法 doExecute 来实现。

我们来看一下 SelectorData 再 admin 页面的直接体现,选择器列表:

在这里插入图片描述

上面图片中有个关键的状态 “open”,这个状态在代码中的使用(matchSelector 方法在会在模板方法 execute 中被调用):

private SelectorData matchSelector(final ServerWebExchange exchange, final Collection<SelectorData> selectors) {
    
    
    return selectors.stream()
    		//这里会过滤掉 open 状态没激活的 selector
            .filter(selector -> selector.getEnabled() && 
            //这是根据 selector 详细信息的配置进行过滤
            filterSelector(selector, exchange))
            .findFirst().orElse(null);
}

选择器详细信息配置:

在这里插入图片描述
这里主要使用 MathType 和 Condtions 两项配置信息来进行过滤:

//对单个 selector 进行匹配
private Boolean filterSelector(final SelectorData selector, final ServerWebExchange exchange) {
    
    
    if (selector.getType() == SelectorTypeEnum.CUSTOM_FLOW.getCode()) {
    
    
        if (CollectionUtils.isEmpty(selector.getConditionList())) {
    
    
            return false;
        }
        // selector.getMatchMode():对应上图的 MathType,匹配策略
        // selector.getConditionList() :很明显就是 Conditions
        return MatchStrategyUtils.match(selector.getMatchMode(), selector.getConditionList(), exchange);
    }
    return true;
}

Rule

紧接着是 Rule 的获取和筛选,其过程和上面的 Selector Data 非常相似。对于Rule 的具体配置,小伙伴们可以直接参考官方文档

和上面一样,我们来看一下 Rule Data 在 Admin 界面的直观体现,Rule List:

在这里插入图片描述
Rule Detail:

在这里插入图片描述
结合上面的两幅图,我们再结合一下其筛选代码(该方法处在模板方法 executor 的调用链路里):

private Boolean filterRule(final RuleData ruleData, final ServerWebExchange exchange) {
    
    
	// 第一个判断:列表中的 open 状态
	// 第二个判断:条件匹配,和 selector data 的逻辑一样
    return ruleData.getEnabled() && MatchStrategyUtils.match(ruleData.getMatchMode(), ruleData.getConditionDataList(), exchange);
}

doExecute

获取并且匹配完 SeletorData 和 Rule 集合后,就可以将它们传递给子类的 doExecutor 方法进行使用了。例如:DividePlugin、ApacheDubboPlugin、SofaPlugin、SpringCloudPlugin、HystrixPlugin、SentinelPlugin 等这些插件都是继承了 AbstractSoulPlugin 并且实现了该父类方法,这样子类就可以直接使用 Seletor 和 Rule 的相关数据了。

总结

这一章节,我们学习了模板类 AbstractSoulPlugin 的处理流程,知道其主要对三样数据进行了获取和过滤:PluginData、SelectorData 和 Rule,并将它们作为参数传递给子类方法 doExecutor 进行使用。后面,我们就开始对这些子类的具体实现进行分析。

猜你喜欢

转载自blog.csdn.net/u012180773/article/details/113069719
今日推荐