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

前言

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

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

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

com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper.buildInvokerChain(Invoker, String, String)

该方法源码如下。

 private static  Invoker buildInvokerChain(final Invoker invoker, String key, String group) {
        Invoker last = invoker;
        List 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 next = last;
                last = new Invoker() {

                    public Class 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 invoker, String key, String group)

调用buildInvokerChain时会传入invoker参数。

Invoker last = invoker; 

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

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

final Invoker next = last;

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

final Invoker next = last;
last = new Invoker(),

结果如下图所示。
dubbo调用链/过滤器链的创建分析_第1张图片

接着通过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方法,这样就完成了结点的串联。

dubbo调用链/过滤器链的创建分析_第2张图片

可以看到链表的最后一个结点就是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 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

你可能感兴趣的:(dubbo)