Soul网关(9) - 插件职责链

371 阅读2分钟

话不多说,上来就干

职责链模式

这一篇来了解一下soul网关中的插件设计机制,职责链模式是面向编程设计模式中的经典模式,具体可以参考职责链模式,职责链简单来说,就是每个接收者都包含另一个接收者的引用,这样在处理请求时,如果自己无法处理该请求时就会把请求,传递给下一个接收者,依次类推直到最后。

类图示例

职责链在soul网关中的应用

加载插件

在soul-web中初始化插件处理器

    @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()));
        //初始化插件链
        return new SoulWebHandler(soulPlugins);
    }

SoulWebHandler实现了spring的WebHandler接口,接口类WebHandler就是插件职责链中顶级接口,只有一个处理方法handle()

public interface WebHandler {
    Mono<Void> handle(ServerWebExchange var1);
}

soul的handle(),调用DefaultSoulPluginChainexecute()

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

我们可以先参考一下spring通过filter.chain方式调用自己的chain处理

	public Mono<Void> filter(ServerWebExchange exchange) {
		return Mono.defer(() ->
				this.currentFilter != null && this.chain != null ?
						invokeFilter(this.currentFilter, this.chain, exchange) :
						this.handler.handle(exchange));
	}

soul自己定义了插件链处理了接口SoulPluginChain,通过DefaultSoulPluginChain实现execute()

        public Mono<Void> execute(final ServerWebExchange exchange) {
            return Mono.defer(() -> {
                if (this.index < plugins.size()) {
                    // index计数
                    SoulPlugin plugin = plugins.get(this.index++);
                    // 判断是否需要调过该插件
                    Boolean skip = plugin.skip(exchange);
                    if (skip) {
                        // 直接再次调用execute(),调用下一个index++的插件
                        return this.execute(exchange);
                    }
                    // 直接执行插件逻辑
                    return plugin.execute(exchange, this);
                }
                return Mono.empty();
            });
        }

优点

职责链模式提高soul插件机制的灵活性,实现解耦

虽然职责链设计本身采用递归调用,在性能上有所损耗,但是soul采用了响应式编程,

/**
     * 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);

响应式编程最大的优点就是摒除了同步阻塞的问题,直接采用异步非阻塞处理机制,大大弥补了责任链递归调用的性能损耗