前言
使用Dubbo时,当调用方法,会通过过滤器对调用进行一些处理。例如超时记录(TimeoutFilter),异常(ExceptionFilter),token(TokenFilter)等处理。这个功能的实现是通过Dubbo内置的Filter或用户自定义的Filter来创建调用链完成。当发起方法调用时,会执行调用链各个结点的方法,以完成一些处理工作。
调用链/过滤器链的创建分析
调用链的构建是通过下面的方法来实现。
com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper.buildInvokerChain(Invoker<T>, String, String)
该方法源码如下。
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
Invoker<T> last = invoker;
List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
if (filters.size() > 0) {
for (int i = filters.size() - 1; i >= 0; i --) {
final Filter filter = filters.get(i);
final Invoker<T> next = last;
last = new Invoker<T>() {
public Class<T> getInterface() {
return invoker.getInterface();
}
public URL getUrl() {
return invoker.getUrl();
}
public boolean isAvailable() {
return invoker.isAvailable();
}
public Result invoke(Invocation invocation) throws RpcException {
return filter.invoke(next, invocation);
}
public void destroy() {
invoker.destroy();
}
@Override
public String toString() {
return invoker.toString();
}
};
}
}
return last;
}
在构建调用链时方法先获取Filter列表,然后创建与Fitler数量一样多Invoker结点,接着将这些结点串联在一起,构成一个链表,最后将这个链的首结点返回,随后的调用中,将从首结点开始,依次调用各个结点,完成调用后沿调用链返回。这里各个Invoker结点的串联是通过与其关联的invoke方法来完成的。接下来分析这个调用链的创建。
buildInvokerChain(final Invoker<T> invoker, String key, String group)
调用buildInvokerChain时会传入invoker参数。
Invoker<T> last = invoker;
通过创建last,来指向头结点。初始状态如下图所示。
接着通过循环遍历获取到的Filter,同时创建Invoker结点,每个结点对应一个Filter。此时循环内部定义了next指针。
final Invoker<T> next = last;
该指针每次更新为指向原链表中的头结点,即last指针。 随后创建新结点,并更新last。此时新结点将作为链表中的头结点。
final Invoker<T> next = last;
last = new Invoker<T>(),
结果如下图所示。
接着通过invoke方法将各个结点串联。
public Result invoke(Invocation invocation) throws RpcException {
return filter.invoke(next, invocation);
}
在该方法内部,通过调用与该invoker关联的filter中的invoke方法来实现结点的连接。调用时将next传入invoke方法,在调用时首先会调用该结点对应的filter的invoke方法,接着调用传入参数next的invoke方法。Next的invoke方法同样会调用自己所关联的filter的invoke方法,这样就完成了结点的串联。
可以看到链表的最后一个结点就是buildInvokerChain 方法的入参invoker。最终buildInvokerChain方法通过链表头插法完成调用链的创建。因此在真正的调用请求处理前会经过若干filter进行预处理。
这里调用链的创建可以看作是职责链模式(Chain of Responsibility Pattern)的一个实现。这样系统中增加一个新的过滤器预处理请求时,无须修改原有系统的代码,只需重新建调用链即可。
一个简化实现
interface Filter{
public int invoke(Invoker invoker);
}
class Filter1 implements Filter{
public int invoke(Invoker invoker) {
System.out.println("Filter1");
invoker.invoke();
return 0;
}
}
class Filter2 implements Filter{
public int invoke(Invoker invoker) {
System.out.println("Filter2");
return invoker.invoke();
}
}
interface Invoker{
public int invoke();
}
public class Main {
public static void main(String[] args) {
List<Filter> filters = Arrays.asList(new Filter1(),new Filter2());
Invoker last = new Invoker() {
public int invoke() {
System.out.println("invoker");
return 0;
}
};
for(int i = filters.size() - 1; i >= 0; i--) {
// 获取filter
final Filter filter = filters.get(i);
final Invoker next = last;
// 更新last
last = new Invoker() {
public int invoke() {
return filter.invoke(next);
}
};
}
last.invoke();
}
}
参考
dubbo源码 2.8.4