dubbo调用链/过滤器链的创建分析

前言

使用Dubbo时,当调用方法,会通过过滤器对调用进行一些处理。例如超时记录(TimeoutFilter),异常(ExceptionFilter),token(TokenFilter)等处理。这个功能的实现是通过Dubbo内置的Filter或用户自定义的Filter来创建调用链完成。当发起方法调用时,会执行调用链各个结点的方法,以完成一些处理工作。

调用链/过滤器链的创建分析

调用链的构建是通过下面的方法来实现。

com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper.buildInvokerChain(Invoker<T>, String, String)
  • 1

该方法源码如下。

 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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

在构建调用链时方法先获取Filter列表,然后创建与Fitler数量一样多Invoker结点,接着将这些结点串联在一起,构成一个链表,最后将这个链的首结点返回,随后的调用中,将从首结点开始,依次调用各个结点,完成调用后沿调用链返回。这里各个Invoker结点的串联是通过与其关联的invoke方法来完成的。接下来分析这个调用链的创建。

buildInvokerChain(final Invoker<T> invoker, String key, String group)
  • 1

调用buildInvokerChain时会传入invoker参数。

Invoker<T> last = invoker; 
  • 1

通过创建last,来指向头结点。初始状态如下图所示。 
这里写图片描述

接着通过循环遍历获取到的Filter,同时创建Invoker结点,每个结点对应一个Filter。此时循环内部定义了next指针。

final Invoker<T> next = last;
  • 1

该指针每次更新为指向原链表中的头结点,即last指针。 随后创建新结点,并更新last。此时新结点将作为链表中的头结点。

final Invoker<T> next = last;
last = new Invoker<T>(),
  • 1
  • 2

结果如下图所示。 
这里写图片描述

接着通过invoke方法将各个结点串联。

public Result invoke(Invocation invocation) throws RpcException {
                        return filter.invoke(next, invocation);
}
  • 1
  • 2
  • 3
  • 4

在该方法内部,通过调用与该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();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

参考

dubbo源码 2.8.4

猜你喜欢

转载自blog.csdn.net/yangxiaobo118/article/details/80715958