Soul网关-day12
Soul-plugin-divide测试(二)
昨天测试了soul-plugin-divide的基本功能,下面来研究一下divide的负载均衡策略。
首先在整个soul项目中搜索叫LoadBalance的类,可以看到LoadBalance类是在org.dromara.soul.plugin.divide.balance包下,是一个被@SPI修饰接口:
@SPI
public interface LoadBalance {
/**
* this is select one for upstream list.
*
* @param upstreamList upstream list
* @param ip ip
* @return divide upstream
*/
DivideUpstream select(List<DivideUpstream> upstreamList, String ip);
}
这个是在soul-plugin项目下的soul-plugin-divide子项目中的接口,并且用到了java中的SPI机制,所以我们找到这个子项目,看看soul主要加载了什么类作为负载均衡的。
在src/mian/resources/META-INF.soul下可以看到有一个LoadBalance全限定类名的文件,文件的内容如下:
random=org.dromara.soul.plugin.divide.balance.spi.RandomLoadBalance
roundRobin=org.dromara.soul.plugin.divide.balance.spi.RoundRobinLoadBalance
hash=org.dromara.soul.plugin.divide.balance.spi.HashLoadBalance
既然知道有哪些类了,接下来就看在哪里调用这些类;既然它有这个接口类,那么程序设计里大概就是直接调用这个接口了,要不然代码就太冗余了。所以我们找到了这个接口调用类(LoadBalanceUtils),可以看到这个Utils中只有一个方法:
/**
* Selector divide upstream.
*
* @param upstreamList the upstream list
* @param algorithm the loadBalance algorithm
* @param ip the ip
* @return the divide upstream
*/
public static DivideUpstream selector(final List<DivideUpstream> upstreamList, final String algorithm, final String ip) {
LoadBalance loadBalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getJoin(algorithm);
return loadBalance.select(upstreamList, ip);
}
这个方法大概的含义是:从ClassLoader中拿到我们指定的负载均衡算法,这个算法肯定是LoadBalance的子类,所以可以被直接赋值为LoadBalance。
拿到了这个loadBalance以后,就直接调用loadBalance中的select方法。这个方法按理论来说就是返回一个请求目标地址,根据这个方法看来就是返回一个DivideUpstream的类型。
既然返回的是这么个东西,大概知道是有这么个作用;那我们可以开始好奇,这个类是在哪里用到的?拿到以后这个类又起到了怎么哥作用呢?接下来看DividePlugin这个类:
public class DividePlugin extends AbstractSoulPlugin {
}
可以看到这个类又是继承了一个抽象类,结合Soul网关中有多种插件,可以合理地进行推测,大概注册插件就是依赖于这个AbstractSoulPlugin(不一定准,但应该差不离,水下一篇的时候考虑去看下)。
看这个类是在哪里调用LoadBalanceUtils的selector的,拿到了结果以后又是拿去干什么了呢?代码如下:
protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
//省略前面的代码
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);
}
大概拿到这个DivideUpstream以后,因该就是用DivideUpstream这个类中的属性来构建Http请求了。而这里的返回值为chain.execute(exchange),这个值是一个Mono的类,猫大人以前介绍过,这个类Reactor中用的比较多,而后面的泛型昭示着这个其实是没有返回值的,大概就是发送一个http请求了。
…maybe Continue