学习目标:
1.插件定义
2.插件处理
学习内容:
1.插件定义
2.插件处理
学习时间:
2020年1月31号
学习产出:
- 插件定义
插件是soul的核心概念,包含鉴权,限流,熔断,防火墙插件;soul 的特性都是基于插件实现的, soul 中插件的接口定义在模块 soul-plugin-api 中, 其主要的方法如下:
public interface SoulPlugin {
/**
* Process the Web request and (optionally) delegate to the next
* {@code WebFilter} through the given {@link SoulPluginChain}.
*
* @param exchange the current server exchange
* @param chain provides a way to delegate to the next filter
* @return {@code Mono<Void>} to indicate when request processing is complete
*/
Mono<Void> execute(ServerWebExchange exchange, SoulPluginChain chain);
/**
* return plugin order .
* This attribute To determine the plugin execution order in the same type plugin.
*
* @return int order
*/
int getOrder();
/**
* acquire plugin name.
* this is plugin name define you must Provide the right name.
* if you impl AbstractSoulPlugin this attribute not use.
*
* @return plugin name.
*/
default String named() {
return "";
}
/**
* plugin is execute.
* if return true this plugin can not execute.
*
* @param exchange the current server exchange
* @return default false.
*/
default Boolean skip(ServerWebExchange exchange) {
return false;
}
}
1. execute 方法定义了 soul 插件逻辑的执行入口
2. getOrder 约束接口要求了所有的实现类需要在这个接口的实现里面返回 int 类型的插件顺序, 这个顺序在组织网关的插件链的时候会决定网关请求上下文在插件处理链上的处理的顺序
3. named 约束接口要求了所有的实现类需要在这个接口的实现里面返回插件的名称
4. skip 接口根据传入的 ServerWebExchange 中的网关请求上下文信息判断是否跳过一个插件的处理
getOrder 详解:
SoulConfiguration初始化时根据order决定插件的加载顺序:
@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);
}
- 插件处理
soul-web 模块中的 SoulWebHandler 是处理 soul 网关请求的关键类, 在它的 execute 方法中, 可以看到它会实例化 DefaultSoulPluginChain 对象后然后调用它的 execute 方法, DefaultSoulPluginChain 对象的 execute 方法如下:
public final class SoulWebHandler implements WebHandler {
private final List<SoulPlugin> plugins;
private final Scheduler scheduler;
/**
* Instantiates a new Soul web handler.
*
* @param plugins the plugins
*/
public SoulWebHandler(final List<SoulPlugin> plugins) {
this.plugins = plugins;
String schedulerType = System.getProperty("soul.scheduler.type", "fixed");
if (Objects.equals(schedulerType, "fixed")) {
int threads = Integer.parseInt(System.getProperty(
"soul.work.threads", "" + Math.max((Runtime.getRuntime().availableProcessors() << 1) + 1, 16)));
scheduler = Schedulers.newParallel("soul-work-threads", threads);
} else {
scheduler = Schedulers.elastic();
}
}
/**
* Handle the web server exchange.
*
* @param exchange the current server exchange
* @return {@code Mono<Void>} to indicate when request handling is complete
*/
@Override
public Mono<Void> handle(@NonNull final ServerWebExchange exchange) {
MetricsTrackerFacade.getInstance().counterInc(MetricsLabelEnum.REQUEST_TOTAL.getName());
Optional<HistogramMetricsTrackerDelegate> startTimer = MetricsTrackerFacade.getInstance().histogramStartTimer(MetricsLabelEnum.REQUEST_LATENCY.getName());
return new DefaultSoulPluginChain(plugins).execute(exchange).subscribeOn(scheduler)
.doOnSuccess(t -> startTimer.ifPresent(time -> MetricsTrackerFacade.getInstance().histogramObserveDuration(time)));
}
private static class DefaultSoulPluginChain implements SoulPluginChain {
private int index;
private final List<SoulPlugin> plugins;
/**
* Instantiates a new Default soul plugin chain.
*
* @param plugins the plugins
*/
DefaultSoulPluginChain(final List<SoulPlugin> plugins) {
this.plugins = plugins;
}
/**
* Delegate to the next {@code WebFilter} in the chain.
*
* @param exchange the current server exchange
* @return {@code Mono<Void>} to indicate when request handling is complete
*/
@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();
});
}
}
}
execute 方法中使用了 Mono 对象的静态方法 defer,Mono 对象被 subscribe 的时候才会调用 defer 方法的入参, 它的入参对象是个 Supplier。这个 Supplier 方法体的内部执行的就是插件链中插件链条的处理逻辑:
- 每次请求都会实例化一个DefaultSoulPluginChain,多个插件之间互不干扰;
- 一个请求执行到插件链的进度由 DefaultSoulPluginChain 对象实例中的 index 标识
- 通过 SoulPlugin 的 skip 方法判断是否跳过当前插件的处理
跳过处理的方法是调用当前实例的 execute 方法,因为 index 变量已经自增, 所以跳过处理调用当前实例的 execute 方法之后会处理插件链条中当前插件节点的下一个插件节点
如果不跳过处理, 执行插件的 execute 方法, ServerWebExchange 信息和当前的插件链信息传入让插件链往下执行