一、前戏
本篇文章,将梳理soul作为网关的核心功能,请求处理、转发、响应的整个过程。
二、责任链
通过前几篇的源码学习,知道了soul的请求相关处理的多个模块,是基于责任链模式。以达到插件式热插拔,高内聚低耦合易扩展的特性。
- 责任链模式的概念
多个处理器(也就是刚刚定义中说的“接收对象”)依次处理同一个请求。一个请求先经过 A 处理器处理,然后再把请求传递给 B 处理器,B 处理器处理完后再传递给 C 处理器,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理职责,所以叫作职责链模式。
soul的职责链是通过数组实现的,而非链表。为了便于后文的理解,此处放一个code demo。
public interface IHandler {
boolean handle();
}
public class HandlerA implements IHandler {
@Override
public boolean handle() {
boolean handled = false;
//...
return handled;
}
}
public class HandlerB implements IHandler {
@Override
public boolean handle() {
boolean handled = false;
//...
return handled;
}
}
public class HandlerChain {
private List handlers = new ArrayList<>();
public void addHandler(IHandler handler) {
this.handlers.add(handler);
}
public void handle() {
for (IHandler handler : handlers) {
boolean handled = handler.handle();
if (handled) {
break;
}
}
}
}
// 使用举例
public class Application {
public static void main(String[] args) {
HandlerChain chain = new HandlerChain();
chain.addHandler(new HandlerA());
chain.addHandler(new HandlerB());
chain.handle();
- soul中的责任链如何构建?
在SoulConfiguration(soul-web)中soulWebHandler方法
通过ObjectProvider加载所有SoulPlugin的实现类,并按照order进行排序,确定责任链的执行顺序。
- 责任链的调用 -- DefaultSoulPluginChain
public Mono execute(final ServerWebExchange exchange) {
return Mono.defer(() -> {
if (this.index < plugins.size()) {
// 获取当前需要执行的 SoulPlugin 插件,同时index++
SoulPlugin plugin = plugins.get(this.index++);
//如果插件需要跳过,则直接递归调用本身,相当于调用下一个插件
Boolean skip = plugin.skip(exchange);
if (skip) {
return this.execute(exchange);
}
//exchange 和 插件链本身(this)做为方法参数
return plugin.execute(exchange, this);
}
return Mono.empty();
});
}
plugins中包含当前需要执行的所有插件,通过递增偏移量index,取出插件。如果插件需要跳过,则递归调用execute方法,不跳过执行当前插件的execute方法。
把当前调用链实例this作为传参数,在AbstractSoulPlugin##doExecute或其实现类中***Plugin##doExecute中调用chain.execute,从而继续执行下一个插件。
@Override
protected Mono doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
// some code
return chain.execute(exchange);
}
SoulWebHandler中总共有17个调用链,调用顺序如下
GlobalPlugin
SignPlugin
WafPlugin
RateLimiterPlugin
HystrixPlugin
Resilience4JPlugin
DividePlugin
WebClientPlugin
WebSocketPlugin
BodyParamPlugin
BodyParamPlugin
SofaPlugin
AlibabaDubboPlugin
MonitorPlugin
WebClientResponsePlugin
SofaResponsePlugin
DubboResponsePlugin
- skip与enabled
AbstractSoulPlugin##execut,根据admin-soul设置插件的启用/停用,动态判断
****Plugin##skip,用于判断当前强求是否属于当前插件职责范围内,静态判断
- Mono.defer(() )
异步非阻塞的响应式编程,保证了soul能用对高并发
科普贴:https://zhuanlan.zhihu.com/p/92460075
三、请求转发路径探索
责任链调用,其实是请求链路的中后处理过程。下面debug调试下,梳理整条完整路径
1.SoulWebHandler#execute挂上断点,postman发起一下请求,通过调用栈向上查找
2.来到DefaultWebFilterChain,继续挂上断点,postman发起一下请求
3.深挖调用栈我们来到熟悉的netty的处理类
梳理下前半段接收请求的流程
HttpServerOperations : netty的请求入口
TcpServerBind
HttpServerHandle
ReactorHttpHandlerAdapter :生成response和request
ReactiveWebServerApplicationContext
HttpWebHandlerAdapter :ServerWebExchange
exchange 的生成
ExceptionHandlingWebHandler
WebHandlerDecorator
FilteringWebHandler
DefaultWebFilterChain
SoulWebHandler :plugins调用链
整体调用链如下:
四、小结
- 从整个调用链中部责任链切入,先捋清下游责任链的调用关系。再追加断点调试打法,一点点的向上搜寻,最终完成描绘出整条链路
- 后续文章将对17个插件,逐个分析
- 日拱一卒,每天进步一点点