Dubbo源码- 服务调用过程

本文深入分析了Dubbo服务调用的全过程,包括服务消费者如何通过Proxy发起调用,请求如何经过网络层到达服务提供方,服务提供方如何接收并处理请求,以及调用结果如何返回给消费者。详细探讨了同步和异步调用方式,特别是异步调用的实现机制。此外,还讲解了线程派发模型和服务调用路径,揭示了Dubbo服务调用的内部机制。
摘要由CSDN通过智能技术生成

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
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值