插件原理图
插件就是一个一个的功能模块,比如:
monitor:监控请求模块
divide:支持http的请求转发
dubbo:支持rpc的请求转发
sign:请求进来的签名验证
hystrix:限流降级插件
等等…
插件是soul核心处理机制,每当一次请求进来时,Soul 通过责任链模式,依次执行责任链上的所有插件,完成请求的处理。
插件的特性:支持热插拨、可扩展
插件加载
网关启动的时候,插件列表被加载到内存
加载到内存的插件为:
这些插件是怎么加载的呢?
插件默认是在soul-bootstrap中配置的:
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-spring-boot-starter-plugin-divide</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-spring-boot-starter-plugin-alibaba-dubbo</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-spring-boot-starter-plugin-ratelimiter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-spring-boot-starter-plugin-hystrix</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-spring-boot-starter-plugin-waf</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-spring-boot-starter-plugin-sign</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-spring-boot-starter-plugin-httpclient</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-spring-boot-starter-plugin-resilience4j</artifactId>
<version>${project.version}</version>
</dependency>
soul-web网关核心程序中配置了global插件
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-spring-boot-starter-plugin-global</artifactId>
<version>${project.version}</version>
</dependency>
然后应用启动是,通过各个载入的starter插件的Configuration,在插件配置类中,实例化插件到容器
上图只是列举了GlobalPlugin
,其它14个插件都是通过各自的配置类,实例化到容器中。
最后通过SoulConfiguration
配置类,将插件列表加入到SoulWebHandler
中:
通过(final ObjectProvider<List<SoulPlugin>> plugins)
,将所有继承了SoulPlugin
的 并且已经 加载到容器的插件注入进来
public class SoulConfiguration {
/**
* Init SoulWebHandler.
*
* @param plugins this plugins is All impl SoulPlugin.
* @return {@linkplain SoulWebHandler}
*/
@Bean("webHandler")
public SoulWebHandler soulWebHandler(final ObjectProvider<List<SoulPlugin>> plugins) {
// 获取所有可用插件
List<SoulPlugin> pluginList = plugins.getIfAvailable(Collections::emptyList);
// 把插件按照配置order进行排序
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()));
// 初始化SoulWebHandler类
return new SoulWebHandler(soulPlugins);
}
......
}
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;
// TODO:线程调度相关
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();
}
}
......
}
至此,
0 = {GlobalPlugin@7938}
1 = {SignPlugin@10092}
2 = {WafPlugin@10093}
3 = {RateLimiterPlugin@10094}
4 = {HystrixPlugin@10095}
5 = {Resilience4JPlugin@10096}
6 = {DividePlugin@7993}
7 = {WebClientPlugin@9890}
8 = {WebSocketPlugin@10097}
9 = {BodyParamPlugin@10098}
10 = {AlibabaDubboPlugin@10099}
11 = {MonitorPlugin@10100}
12 = {DubboResponsePlugin@10101}
13 = {WebClientResponsePlugin@9998}
动态地把所有需要的插件载入到了SoulWebHandler
(soul网关web请求调度器中)的plugins
属性中。
而被载入的插件,是有顺序的。
// 把插件按照配置order进行排序
final List<SoulPlugin> soulPlugins = pluginList.stream()
.sorted(Comparator.comparingInt(SoulPlugin::getOrder)).collect(Collectors.toList());
各个插件顺序,已被定义在一个PluginEnum
枚举类型里:
@RequiredArgsConstructor
@Getter
public enum PluginEnum {
/**
* Global plugin enum.
*/
GLOBAL(1, 0, "global"),
/**
* Sign plugin enum.
*/
SIGN(2, 0, "sign"),
/**
* Waf plugin enum.
*/
WAF(10, 0, "waf"),
/**
* Rate limiter plugin enum.
*/
RATE_LIMITER(20, 0, "rate_limiter"),
/**
* Context path mapping plugin enum.
*/
CONTEXTPATH_MAPPING(25, 0, "context_path"),
/**
* Rewrite plugin enum.
*/
REWRITE(30, 0, "rewrite"),
/**
* Redirect plugin enum.
*/
REDIRECT(40, 0, "redirect"),
/**
* Hystrix plugin enum.
*/
HYSTRIX(45, 0, "hystrix"),
/**
* Sentinel plugin enum.
*/
SENTINEL(45, 0, "sentinel"),
/**
* Resilence4J plugin enum.
*/
RESILIENCE4J(45, 0, "resilience4j"),
/**
* Divide plugin enum.
*/
DIVIDE(50, 0, "divide"),
/**
* springCloud plugin enum.
*/
SPRING_CLOUD(50, 0, "springCloud"),
/**
* webSocket plugin enum.
*/
WEB_SOCKET(55, 0, "webSocket"),
/**
* Dubbo plugin enum.
*/
DUBBO(60, 0, "dubbo"),
/**
* Sofa plugin enum.
*/
SOFA(60, 0, "sofa"),
/**
* Tars plugin enum.
*/
TARS(60, 0, "tars"),
/**
* Monitor plugin enum.
*/
MONITOR(80, 0, "monitor"),
/**
* Response plugin enum.
*/
RESPONSE(100, 0, "response");
插件请求处理
每一个http请求过来,SoulWebHandler
会处理请求:
@Override
public Mono<Void> handle(@NonNull final ServerWebExchange exchange) {
// TODO:指标监控相关
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)));
}
接着DefaultSoulPluginChain
中开启执行请求:
private static class DefaultSoulPluginChain implements SoulPluginChain {
private int index;
private final List<SoulPlugin> plugins;
......
@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();
});
}
}
}
依次执行插件:
0 = {GlobalPlugin@7938}
1 = {SignPlugin@10092}
2 = {WafPlugin@10093}
3 = {RateLimiterPlugin@10094}
4 = {HystrixPlugin@10095}
5 = {Resilience4JPlugin@10096}
6 = {DividePlugin@7993}
7 = {WebClientPlugin@9890}
8 = {WebSocketPlugin@10097}
9 = {BodyParamPlugin@10098}
10 = {AlibabaDubboPlugin@10099}
11 = {MonitorPlugin@10100}
12 = {DubboResponsePlugin@10101}
13 = {WebClientResponsePlugin@9998}
已被加载的插件关系图如下:
soul就是通过责任链的模式,执行每个插件的处理:
1)直接继承SoulPlugin
接口的,执行各自插件的execute
方法,处理插件逻辑
2)继承AbstractSoulPlugin
抽象方法的,执行AbstractSoulPlugin
的execute
方法,执行完之后,路由规则匹配没问题,在执行各自的插件的doExecute
方法
3)最后通过插件WebClientResponsePlugin
,将请求响应返回给用户。
至此,整个插件处理完成。