soul网关入门 之插件化架构 第五章

1,097 阅读2分钟

​ 前几章学习了把 基于http、dubbo、sofa、springcloud 这些协议或者rpc框架开发的应用服务接入soul网关的实践以及看代码和思考得到以下几点心得。

1、soul网关总体架构采用微内核架构,也被称为插件化架构。上面提到的四种协议或rpc接入网关就分别引入了四种插件,以支持http的divide插件为例子。

<!--if you use http proxy start this-->
<dependency>
    <groupId>org.dromara</groupId>
    <artifactId>soul-spring-boot-starter-plugin-divide</artifactId>
    <version>${project.version}</version>
</dependency>

通过在pom中加入依赖的方式就可引入插件,这种方式非常灵活,轻松实现代码层面可插拔,并且还可以在soul网关的控制台控制是否启用该插件。

@Configuration
@ComponentScan("org.dromara.soul")
@Import(value = {ErrorHandlerConfiguration.class, SoulExtConfiguration.class, SpringExtConfiguration.class})
@Slf4j
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);
        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);
    }
 }

从上面代码看出,所有的插件都会被注入一个list的参数里,SoulPlugin 是插件接口,AbstractSoulPlugin 抽象类实现了SoulPlugin 接口 ,具体的插件类 DividePlugin继承了AbstractSoulPlugin,所以当SoulWebHandler被spring容器实例化时会扫描所有的具体插件类加载进来。

2、模板模式的运用

查看AbstractSoulPlugin类

@RequiredArgsConstructor
@Slf4j
public abstract class AbstractSoulPlugin implements SoulPlugin {

    /**
     * this is Template Method child has Implement your own logic.
     *
     * @param exchange exchange the current server exchange {@linkplain ServerWebExchange}
     * @param chain    chain the current chain  {@linkplain ServerWebExchange}
     * @param selector selector    {@linkplain SelectorData}
     * @param rule     rule    {@linkplain RuleData}
     * @return {@code Mono<Void>} to indicate when request handling is complete
     */
    protected abstract Mono<Void> doExecute(ServerWebExchange exchange, SoulPluginChain chain, SelectorData selector, RuleData rule);

    /**
     * Process the Web request and (optionally) delegate to the next
     * {@code SoulPlugin} through the given {@link SoulPluginChain}.
     *
     * @param exchange the current server exchange
     * @param chain    provides a way to delegate to the next plugin
     * @return {@code Mono<Void>} to indicate when request processing is complete
     */
    @Override
    public Mono<Void> execute(final ServerWebExchange exchange, final SoulPluginChain chain) {
        String pluginName = named();
        final PluginData pluginData = BaseDataCache.getInstance().obtainPluginData(pluginName);
        if (pluginData != null && pluginData.getEnabled()) {
            // 省略若干检查作用的代码
          // 符合条件执行本插件逻辑
            return doExecute(exchange, chain, selectorData, rule);
        }
      // 本插件不满足执行条件,比如本插件已经close等,交由chain调用下一个插件执行
        return chain.execute(exchange);
    }

}

protected abstract Mono<Void> doExecute(ServerWebExchange exchange, SoulPluginChain chain, SelectorData selector, RuleData rule);方法留给具体插件类实现。

execute方法 是模板方法,各个插件都要执行的逻辑。

3、各插件的轮询执行

    private static class DefaultSoulPluginChain implements SoulPluginChain {

        private int index;
        // 所有插件装到list 里
        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();
            });
        }
    }
}

总结:以上是soul网关插件大致执行流程。