24.调用链如何构建的?ProtocolFilterWrapper分析

调用链的构建,可以理解成多个invoker实例组成链的构建。

调用链构建在dubbo中分为两步骤:

  1. JavassistProxyFactory$1的构建。此步骤是将真正的业务方法同规避反射的手段包起来。
  2. ProtocolFilterWrapper$1的构建。此步骤是将每个filter用Invoker实例包起来并串起来链来。

具体代码和示意图参见下面

代码

JavassistProxyFactory$1的构建代码

// JavassistProxyFactory
// public class JavassistProxyFactory extends AbstractProxyFactory
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // TODO Wrapper类不能正确处理带$的类名
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName, 
                                      Class<?>[] parameterTypes, 
                                      Object[] arguments) throws Throwable {
                return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
            }
        };
    }

ProtocolFilterWrapper$1的构建代码

// ProtocolFilterWrapper 
// public class ProtocolFilterWrapper implements Protocol
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;
    }

构建图示

ProtocolFilterWrapper$1的构建图示

        filter * n
   +-+-+                                                        +-+-+
 ①   |  +----------+   +----------+   +----------+  +----------+  |
     |  | filter0  <----|filter1  <---+ filter2  <---|filtern  |  |
     |  +----------+   +----------+   +----------+  +----------+  |
   +-+-+                                                        +-+-+
                                     <-------------------------+
  +----------------------------------------+                ②  |
    ③   JavassistProxyFactory$1            |                   |
                                           |                   |
                      +             +      |                   |
             +--------+  inVoker    |      |                   |
             |        +--------------------v----+              |
             |        |   filtern   |  next     |              |
             |        +-------------+-----------+              |
             |                                                 |
             +-----------------------------+                   |
                                           |                   |
build                 +             +      |                   |
Invoker      +--------+  inVoker    |      |                   |
Chain        |        +--------------------v----+              |
             |        |   filter2   |  next     |              |
             |        +-------------+-----------+              |
             |                                                 |
             +-----------------------------+                   |
                                           |                   |
                      +             +      |                   |
             +--------+  inVoker    |      |                   |
             |        +--------------------v----+              |
             |        |   filter1   |  next     |              |
             |        +-------------+-----------+              |
             |                                                 |
             +-----------------------------+                   |
                                           |                   |
                      +             +      |                   |
             +--------+  inVoker    |      |                   |
             |        +--------------------v----+              |
             |        |   filter0   |  next     |              v
             |        +-------------+-----------+
             |
             |
  <----------+
    ④  ProtocolFilterWrapper$1

解释

JavassistProxyFactory$1的构建解释

此步骤是将真正的业务方法同规避反射的手段包起来。具体实现逻辑在:

final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);

这个通过动态生成生成的Wrapper通过直接调用业务类方法规避了反射调用。具体细节和生成的代码可以参见《反射调用是如何优化的?Wrapper的作用是什么?》。

ProtocolFilterWrapper$1的构建解释

从③处将JavassistProxyFactory$1送进来到④处将ProtocolFilterWrapper$1送出去之间,就是构建调用链的整个过程。

构建过程中倒序迭代过滤器,将每一个过滤器用invoker匿名内部类包起来,并结合外围变量next组成一个类似闭包的样子,通过每次切换外围next变量的指向形成链。迭代过程中,每次next都指向上一次构建invoker匿名内部类包起来的闭包。

为啥要倒序迭代?因为这样能达成调用时正序迭代,结合调用时调用栈能看的更清楚。