1.8.2.1 基礎(chǔ)類
Soul 中充滿了各種各樣的插件,插件極大地豐富了 Soul 的功能,而且插件支持熱插拔,可擴(kuò)展新極高,Soul 大方部分功能都是基于插件進(jìn)行實(shí)現(xiàn)的。我們先來(lái)看一下 Soul 插件的抽象接口 SoulPlugin 的繼承關(guān)系:
我們可以看到 SoulPlugin 下又非常多的實(shí)現(xiàn)類,我們?cè)倏匆幌?DividePlugin 的繼承情況。
DividePlugin 繼承了AbstractSoulPlugin ,AbstractSoulPlugin 再實(shí)現(xiàn)了 SoulPlugin 接口。我們先看一下 SoulPlugin 有哪些方法:
- execute 插件到執(zhí)行方法,這里傳入 Exchange 即各個(gè)插件之間進(jìn)行通信到橋梁, Chain 插件鏈。
- getOrder 返回各個(gè)插件到執(zhí)行順序。我們看 SoulConfiguration 這里是Soul 的核心代碼,這里配置了對(duì)應(yīng)的WebHandler ,它是所有插件的起點(diǎn)。我們接下來(lái)將 webFulx 會(huì)講到。WebHandler 會(huì)根據(jù)Order 由小到大排列,定義各個(gè)插件的處理順序。
@Bean("webHandler")
public SoulWebHandler soulWebHandler(final ObjectProvider<List<SoulPlugin>> plugins) {
List<SoulPlugin> pluginList = plugins.getIfAvailable(Collections::emptyList);
final List<SoulPlugin> soulPlugins = pluginList.stream()
.sorted(Comparator.comparingInt(SoulPlugin::getOrder)).collect(Collectors.toList());
soulPlugins.forEach(soulPlugin -> log.info("load plugin:[{}] [{}]", soulPlugin.named(), soulPlugin.getClass().getName()));
return new SoulWebHandler(soulPlugins);
}
- name 返回插件名。
-
skip 定義是否需要跳過(guò)該插件。
我們接著看 AbstractSoulPlugin 的方法。
image.png
我們先來(lái)看一下最重要的 Excute規(guī)則,這是個(gè) Default 方法,但做完 Selector 和 Rule 的匹配后,我們直接執(zhí)行 doExecute 方法,這個(gè)方法需要各個(gè)子類實(shí)現(xiàn)。
@Override
public Mono<Void> execute(final ServerWebExchange exchange, final SoulPluginChain chain) {
String pluginName = named();
// 獲取數(shù)據(jù)
final PluginData pluginData = BaseDataCache.getInstance().obtainPluginData(pluginName);
// 判斷是否開(kāi)啟插件
if (pluginData != null && pluginData.getEnabled()) {
// 獲取選擇器
final Collection<SelectorData> selectors = BaseDataCache.getInstance().obtainSelectorData(pluginName);
if (CollectionUtils.isEmpty(selectors)) {
return handleSelectorIsNull(pluginName, exchange, chain);
}
//查看是否匹配
final SelectorData selectorData = matchSelector(exchange, selectors);
if (Objects.isNull(selectorData)) {
return handleSelectorIsNull(pluginName, exchange, chain);
}
selectorLog(selectorData, pluginName);
// 獲取規(guī)則
final List<RuleData> rules = BaseDataCache.getInstance().obtainRuleData(selectorData.getId());
if (CollectionUtils.isEmpty(rules)) {
return handleRuleIsNull(pluginName, exchange, chain);
}
RuleData rule;
// 查找規(guī)則,假如是全局匹配則直接取最后一個(gè)規(guī)則
if (selectorData.getType() == SelectorTypeEnum.FULL_FLOW.getCode()) {
//get last
rule = rules.get(rules.size() - 1);
} else {
rule = matchRule(exchange, rules);
}
if (Objects.isNull(rule)) {
return handleRuleIsNull(pluginName, exchange, chain);
}
ruleLog(rule, pluginName);
// 真正執(zhí)行規(guī)則
return doExecute(exchange, chain, selectorData, rule);
}
return chain.execute(exchange);
}
我們接著看 DividePlugin 做了啥,其主要是向數(shù)據(jù)交換區(qū)塞入了一部分?jǐn)?shù)據(jù)。包括最終訪問(wèn)的地址,超時(shí)時(shí)間,重試次數(shù)。
@Override
protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
// 獲取上下文存根
final SoulContext soulContext = exchange.getAttribute(Constants.CONTEXT);
assert soulContext != null;
final DivideRuleHandle ruleHandle = GsonUtils.getInstance().fromJson(rule.getHandle(), DivideRuleHandle.class);
// 獲取下游服務(wù)列表
final List<DivideUpstream> upstreamList = UpstreamCacheManager.getInstance().findUpstreamListBySelectorId(selector.getId());
if (CollectionUtils.isEmpty(upstreamList)) {
log.error("divide upstream configuration error: {}", rule.toString());
Object error = SoulResultWrap.error(SoulResultEnum.CANNOT_FIND_URL.getCode(), SoulResultEnum.CANNOT_FIND_URL.getMsg(), null);
return WebFluxResultUtils.result(exchange, error);
}
final String ip = Objects.requireNonNull(exchange.getRequest().getRemoteAddress()).getAddress().getHostAddress();
// 根據(jù)負(fù)載均衡策略篩選下游服務(wù)器列表
DivideUpstream divideUpstream = LoadBalanceUtils.selector(upstreamList, ruleHandle.getLoadBalance(), ip);
if (Objects.isNull(divideUpstream)) {
log.error("divide has no upstream");
Object error = SoulResultWrap.error(SoulResultEnum.CANNOT_FIND_URL.getCode(), SoulResultEnum.CANNOT_FIND_URL.getMsg(), null);
return WebFluxResultUtils.result(exchange, error);
}
// set the http url
String domain = buildDomain(divideUpstream);
String realURL = buildRealURL(domain, soulContext, exchange);
exchange.getAttributes().put(Constants.HTTP_URL, realURL);
// set the http timeout
exchange.getAttributes().put(Constants.HTTP_TIME_OUT, ruleHandle.getTimeout());
exchange.getAttributes().put(Constants.HTTP_RETRY, ruleHandle.getRetry());
return chain.execute(exchange);
}
最終調(diào)用了 chain.execute(exchange) 方法,我們?cè)賮?lái)看看調(diào)用鏈?zhǔn)窃趺磳?shí)現(xiàn)的。DefaultSoulPluginChain 它是 WebHandler 的子類,實(shí)現(xiàn)了 SoulPluginChain 接口,其主要實(shí)現(xiàn)了 execute 方法
@Override
public Mono<Void> execute(final ServerWebExchange exchange) {
return Mono.defer(() -> {
if (this.index < plugins.size()) {
SoulPlugin plugin = plugins.get(this.index++);
Boolean skip = plugin.skip(exchange);
if (skip) {
return this.execute(exchange);
}
return plugin.execute(exchange, this);
}
return Mono.empty();
});
}
這里使用了 Mono.defer 區(qū)別于 Mono.just 是立即執(zhí)行 just 里的 function ,defer 是延遲加載的,當(dāng)每次請(qǐng)求進(jìn)來(lái)都會(huì)生成一個(gè) DefaultSoulPluginChain ,這里記錄了當(dāng)情處理走到了那個(gè) plugin 。
最后我們看一下 SoulWebHandler ,他是所有WebFlux 請(qǐng)求的處理類。
@Bean("webHandler")
public SoulWebHandler soulWebHandler(final ObjectProvider<List<SoulPlugin>> plugins) {
List<SoulPlugin> pluginList = plugins.getIfAvailable(Collections::emptyList);
// 對(duì)插件進(jìn)行排序
final List<SoulPlugin> soulPlugins = pluginList.stream()
.sorted(Comparator.comparingInt(SoulPlugin::getOrder)).collect(Collectors.toList());
// 調(diào)用插件鏈
soulPlugins.forEach(soulPlugin -> log.info("load plugin:[{}] [{}]", soulPlugin.named(), soulPlugin.getClass().getName()));
return new SoulWebHandler(soulPlugins);
}
首先它對(duì)所有對(duì)插件進(jìn)行排序,然后插件鏈,進(jìn)行鏈?zhǔn)秸{(diào)度。