soul源码解读(十四)-- 插件链

17 篇文章 0 订阅

soul源码解读(十四)

soul的插件链

前两天分析 divide 插件的时候,留了个坑,今天就来讲讲 soul 的插件链,把这个坑补上。

我们先看下下面这段代码,已经在前面的文章中出现了几次了,今天就来具体分析分析。

// SoulWebHandler.java
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();
    });
}

这段代码往上找,是 SoulWebHandler#handle

我们发现 SoulWebHandler 实现了 WebHandler

WebHandler 又是 WebFlux 用来处理 web 请求的。(这里再挖一个坑,后面有机会写写 WebFlux 异步编程相关的东西)

soul 实现了 WebHandler ,说明它想用自己的 SoulWebHandler 来处理 web 请求。

然后 SoulWebHandler 里面有个属性 plugins 插件列表,是初始化的时候赋值的,我们接着往上找赋值的地方。

// SoulConfiguration.java
@Bean("webHandler")
public SoulWebHandler soulWebHandler(final ObjectProvider<List<SoulPlugin>> plugins) {
   ...
}

找到了 SoulConfiguration ,它本身配置了 @Configuration ,说明它是一个配置类,在启动之后会被加载。然后它里面配置了 name = “webHandler” 的 bean 。它在初始化的时候,会自动加载所有的插件。

ObjectProvider<List<SoulPlugin>> plugins

我们前面分析过,ObjectProvider 是 spring4.7之后推出来的新功能,有了它,可以不需要再写 @Autowired,然后就算参数为空,也不会报错,它会自动加载所有类型是 SoulPlugin 的bean。

接下来,我们看下 soul 的插件代码,发现 SoulPlugin 是一个接口,它里面有下面4个方法。

	// SoulPlugin.java 
	// 通过插件链执行对应插件对请求的处理
 	Mono<Void> execute(ServerWebExchange exchange, SoulPluginChain chain);
	
	// 获取插件的排序
    int getOrder();
	
	// 获取插件的名字
    default String named() {
        return "";
    }

    // 判断插件是否需要跳过
    default Boolean skip(ServerWebExchange exchange) {
        return false;
    }

然后 AbstractSoulPlugin 实现了 SoulPlugin ,DividePlugin、WebSocketPlugin 等插件又继承了 AbstractSoulPlugin 。

具体类图如下:(idea里查看类图小技巧,接口下右键Diagrams->Show Diagram,选中接口右键Show Implementations
在这里插入图片描述

在这里插入图片描述
可以看到,soul 里面的插件都继承了 AbstractSoulPlugin ,这样网关在启动的时候,就会加载所有 SoulPlugin 的子类,然后根据 order 排序。

// SoulConfiguration#soulWebHandler
    final List<SoulPlugin> soulPlugins = pluginList.stream()
            .sorted(Comparator.comparingInt(SoulPlugin::getOrder)).collect(Collectors.toList());

而order的排序是在 PluginEnum 枚举代码里写死的。

枚举里定义的插件排序如下:
在这里插入图片描述
当一个请求过来之后,会调用 SoulWebHandler#handle

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)));
}

然后请求就会根据初始化排好序的插件列表,循环遍历,是否需要跳过这个插件,是否需要执行插件里的 execute 逻辑。

启动 bootstrap ,把断点打在 SoulWebHandler#SoulWebHandler ,看到插件链如下:
在这里插入图片描述
我们发现加载的插件和定义的插件对不上,很简单,因为有些插件我们没有在 pom 文件里添加依赖。

总结

soul 通过所有插件实现 SoulPlugin 来初始化的时候加载插件列表,然后通过定义好的 order 来指定插件的排序,形成插件链,通过固定排序来实现插件之间的通信。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值