前几章学习了把 基于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网关插件大致执行流程。