1. 前言
Dubbo 服务调用过程比较复杂,包含众多步骤,比如发送请求、编解码、服务降级、过滤器链处理、序列化、线程派发以及响应请求等步骤。限于篇幅原因,本篇文章无法对所有的步骤一一进行分析。后续挖坑再说吧。本篇文章将会重点分析请求的发送与接收、线程派发以及响应的发送与接收等过程。
2. 源码分析
先了解下 Dubbo 服务调用过程(图片来自官方文档)
首先服务消费者通过代理对象 Proxy 发起远程调用,接着通过网络客户端 Client 将编码后的请求发送给服务提供方的网络层上,也就是 Server。Server 在收到请求后,首先要做的事情是对数据包进行解码。然后将解码后的请求发送至分发器 Dispatcher,再由分发器将请求派发到指定的线程池上,最后由线程池调用具体的服务。这就是一个远程调用请求的发送与接收过程。至于响应的发送与接收过程,这张图中没有表现出来。
2.1 服务调用方式
Dubbo 支持同步和异步两种调用方式,其中异步调用还可细分为“有返回值”的异步调用和“无返回值”的异步调用。所谓“无返回值”异步调用是指服务消费方只管调用,但不关心调用结果,此时 Dubbo 会直接返回一个空的 RpcResult。Dubbo 默认使用同步调用方式。
2.1.1 异步调用案例
当有返回值异步和无返回值异步同时存在,无返回值异步优先:
-
有返回值异步调用
修改配置,将参数
async
设置为 true<dubbo:reference id="demoService" check="false" interface="com.alibaba.dubbo.demo.DemoService"> <dubbo:method name="sayHello" async="true" /> </dubbo:reference>
代码使用如下
String hello = demoService.sayHello("world");// 返回值为null,要注意 Future<String> future = RpcContext.getContext().getFuture(); ... // 业务线程可以开始做其他事情 result = future.get();
-
无返回值异步调用
修改配置,将参数
return
设置为 false<dubbo:reference id="demoService" check="false" interface="com.alibaba.dubbo.demo.DemoService"> <dubbo:method name="sayHello" return="false" /> </dubbo:reference>
代码使用
String hello = demoService.sayHello("world");// 返回值为null,要注意 Future<String> future = RpcContext.getContext().getFuture();// future 为 null
下面,我们开始进入源码分析。
2.1.2 InvokerInvocationHandler
当我们通过Spring注入服务接口时,实际上注入的是服务接口的实现类,这个实现类由Dubbo框架生成。请看 服务引用#创建代理对象
package org.apache.dubbo.common.bytecode; public class proxy0 implements org.apache.dubbo.demo.DemoService { public static java.lang.reflect.Method[] methods; private java.lang.reflect.InvocationHandler handler; public proxy0() { } public proxy0(java.lang.reflect.InvocationHandler arg0) { handler = 1; } public java.lang.String sayHello(java.lang.String arg0) { Object[] args = new Object[1]; args[0] = (w) $1; Object ret = handler.invoke(this, methods[0], args); return (java.lang.String) ret; } }
也就是调用 demoService.sayHello 时,实际上是调用 handler.invoke ,而这个 handler 就是 InvokerInvocationHandler
public class InvokerInvocationHandler implements InvocationHandler { private final Invoker<?> invoker; public InvokerInvocationHandler(Invoker<?> handler) { this.invoker = handler; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); Class<?>[] parameterTypes = method.getParameterTypes(); // 拦截定义在 Object 类中的方法(未被子类重写),比如 wait/notify if (method.getDeclaringClass() == Object.class) { return method.invoke(invoker, args); } // 如果 toString、hashCode 和 equals 等方法被子类重写了,这里也直接调用 if ("toString".equals(methodName) && parameterTypes.length == 0) { return invoker.toString(); } if ("hashCode".equals(methodName) && parameterTypes.length == 0) { return invoker.hashCode(); } if ("equals".equals(methodName) && parameterTypes.length == 1) { return invoker.equals(args[0]); } // 将 method 和 args 封装到 RpcInvocation 中,并执行后续的调用 return invoker.invoke(new RpcInvocation(method, args)).recreate(); } }
invoke 方法判断如果是 java 内置的一下方法,则直接调用,不走 dubbo 的逻辑。所以我们关注的是 invoker.invoke() 。类变量 invoker 实际上是 FailoverClusterInvoker
, 但是又被 MockClusterInvoker
包装了一层。这个 FailoverClusterInvoker 是由 FailoverCluster
生成的,请看 服务引用#远程引用 。而 MockClusterInvoker 是由 MockClusterWrapper
生成,其基于Dubbo的SPI机制,将 FailoverCluster 又包装了一遍。 MockClusterInvoker
内部封装了服务降级逻辑。以后再开坑聊。
我们在 Dubbo集群 文章中讲过 FailoverClusterInvoker
,所以直接快进到 DubboInvoker#doInvoke()
方法。此时是不是一脸懵逼,为啥从 FailoverClusterInvoker 一下子就到了 DubboInvoker ,我们先来看看调用栈
我们把视角拉回 FailoverClusterInvoker#doInvoke
,看看通过负载均衡选出的 invoker
从图片可以看到,最外层的invoker是一个内部类,是 服务目录通过订阅注册中心 生成的
invoker = new InvokerDelegate<T>(protocol.refer(serviceType, url), url, providerUrl);
而 protocol 实际是 DubboProtocol
,所以 protocol.refer(serviceType, url) 生成的是 DubboInvoker
,至于为啥调用链这么长,是因为 ProtocolFilterWrapper
,这个类增加了对Dubbo过滤器的支持。这是一个 protocol 的包装类,它包装了DubboProtocol#refer() ,我们取看看 ProtocolFilterWrapper
的源码
@Override public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException { if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { return protocol.refer(type, url); } // 创建invoker链条 return buildInvokerChain(protocol.refer(type, url), Constants.REFERENCE_FILTER_KEY, Constants.CONSUMER); } 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.isEmpty()) { for (int i = filters.size() - 1; i >= 0; i--) { final Filter filter = filters.get(i); final Invoker<T> next = last; // 对invoker进行封装,责任链模式 last = new Invoker<T>() { ...... @Override public Result invoke(Invocation invocation) throws RpcException { return filter.invoke(next, invocation); } }; } } return last; }
buildInvokerChain 方法将 invoker 转换成责任链的形式,获取的 filters 为 {ConsumerContextFilter,FutureFilter,MonitorFilter},和图片中的调用栈就对应上了。
那么还剩下 ListenerInvokerWrapper
,这是一个 Invoker 包装类,由 ProtocolListenerWrapper
生成。
public class ProtocolListenerWrapper implements Protocol { @Override public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException { if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { return protocol.refer(type, url); } // 封装了Invoker监听器 return new ListenerInvokerWrapper<T>(protocol.refer(type, url), Collections.unmodifiableList( ExtensionLoader.getExtensionLoader(InvokerListener.class) .getActivateExtension(url, Constants.INVOKER_LISTENER_KEY))); } } public class ListenerInvokerWrapper<T> implements Invoker<T> { public ListenerInvokerWrapper(Invoker<T> invoker, List<InvokerListener> listeners) { if (invoker == null) { throw new IllegalArgumentException("invoker == null"); } this.invoker = invoker; this.listeners = l