dubbo源码五:服务调用过程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhuqiuhui/article/details/84201687


消费端代码示例(参考incubator-dubbo源码中dubbo-demo模块):

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-consumer.xml"});
context.start();
DemoService demoService = (DemoService) context.getBean("demoService”);

 // 调用远程方法
String hello = demoService.sayHello("world");
System.out.println(hello);

以dubbo分层概念来理解消费端调用过程:
在这里插入图片描述

服务端启动后,消费端引用服务端的接口类会生成一个代理类,即生成InvokerInvocationHandler(invoker)对象实例,所以在调用的时候,会直接调用 InvokerInvocationHandler 的 invoke 方法,
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一、Cluster层

Cluster层作用:封装多个提供者的路由及负载均衡,并桥接注册中心,以Invoker为中心,扩展接口为Cluster、Directory、Router和LoadBalance。将多个服务提供方组合为一个服务提供方,实现对服务消费方来透明,只需要与一个服务提供方进行交互。

根据 https://blog.csdn.net/zhuqiuhui/article/details/84075521 分析知这里的 invoker 是 MockClusterInvoker 实例,即会调用 MockClusterInvoker 的invoke方法,该方法首先判断directory中的url是否含有mock值的设定,若没有设置默认值false。这里的directory中的url的变量是:

multicast://224.5.6.7:1234/org.apache.dubbo.registry.RegistryService?application=demo-consumer&dubbo=2.0.2&pid=28794&qos.port=33333&refer=application%3Ddemo-consumer%26check%3Dfalse%26dubbo%3D2.0.2%26interface%3Dorg.apache.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D28794%26qos.port%3D33333%26register.ip%3D192.168.1.103%26side%3Dconsumer%26timestamp%3D1542519004987×tamp=1542519005031

Debug,如下:
在这里插入图片描述
其中 this.invoker变量值如下:
在这里插入图片描述
上面会调用FailOverClusterInvoker.invoke(),即会调用其父类AbstractClusterInvoker.invoke()的方法。如下:
Debug-1:
在这里插入图片描述
Debug-1 分成以下几个过程:
1. 检查RPC Cluster invoker中要执行的接口是否被销毁,若销毁,则抛出异常。
在这里插入图片描述
2. 在调用提供者之前,会获取当前线程临时变量里的RpcContext对象,再将RpcContext对象里的参数设置到Invocation对象。
在这里插入图片描述
RpcContext 是一个临时状态持有者,每当发请求或者收到请求的时候RpcContext都会发生变化。例如A调用B,然后B调用C,在服务B中,在B调用C之前,RpcContext保存了A调用B的参数。当B调用C的时候,RpcContext保存了B调用C的参数。从源码上看RpcContext对象是绑定在线程临时变量LOCAL上,所以可以通过线程临时变量来获取到RpcContext的相关参数值。
3. 列出所有的Invoker
在这里插入图片描述
在这里插入图片描述
这里可以看到 directory实例是 RegistryDirectory 的实例,会调用其父类的list方法,即如下:
在这里插入图片描述
上面走到RegistryDirectory的doList方法中,其中RegistryDirectory是在消费端服务启动过程中自动会生成RegistryDirectory实例,对应的属性也初始化完成了,即在消费端启动过程时,把方法和对应的invoker关系存放到了RegistryDirectory中的methodInvokerMap属性中(参考:https://blog.csdn.net/zhuqiuhui/article/details/84075521),所以这里,如下:
在这里插入图片描述
其中返回的 invokers 列表如上面的变量。
4. 获取方法上配置的负载均衡策略,若没有配置,选择默认的策略
在这里插入图片描述
常用的配置方法如下:

<dubbo:reference interface="..."loadbalance="roundrobin"/>

在这里插入图片描述
这里返回的 loadbalance 的实例是 RandomLoadBalance 的实例。
5. 幂等操作,即在异步操作中会默认加上invocation ID,不作分析
6. 方法调用
在这里插入图片描述
会走到 FailOverClusterInvoker 中的 doInvoke 方法中,即:
在这里插入图片描述
该方法首先使用负载均衡策略选择合适的invoker(不再分析),然后再进行invoker调用,其中invoker变量如下:
在这里插入图片描述
上面变量的第一行可以看出 invoker 实例是InvokerDelegate实例对象,调用其invoke方法会走到InvokerWrapper的invoke方法,由于InvokerDelegate实例对象中的invoker内部属性是 Invoker 接口的匿名实现,其泛型是ProtocolFilterWrapper类,即如上图中的”ProtocolFilterWrapper$1@3168”,所以会调用”ProtocolFilterWrapper$1@3168”实例invoke方法,看其内部实现:

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;
            last = new Invoker<T>() {

                @Override
                public Class<T> getInterface() {
                    return invoker.getInterface();
                }

                @Override
                public URL getUrl() {
                    return invoker.getUrl();
                }

                @Override
                public boolean isAvailable() {
                    return invoker.isAvailable();
                }

                @Override
                public Result invoke(Invocation invocation) throws RpcException {
                    return filter.invoke(next, invocation);
                }

                @Override
                public void destroy() {
                    invoker.destroy();
                }

                @Override
                public String toString() {
                    return invoker.toString();
                }
            };
        }
    }
    return last;
}

调用的是filter的invoke方法(其中的filter实例是ConsumerContextFilter实例),首先会调用 ConsumerContextFilter 的 invoke 方法,在ConsumerContextFilter 的 invoke 方法中再调用 FutureFilter 的invoke方法,最后在 FutureFilter 的invoke方法中调用 MonitorFilter 的 invoke 方法,MonitorFilter 的 invoke 方法中会调用DubboInvoker 的invoke方法。

二、Protocol 层

Protocol层作用:封装RPC调用,以Invocation和Result为中心,扩展接口为Protocol、Invoker和Exporter。Protocol是服务域,它是Invoker暴露和引用的主功能入口,它负责Invoker的生命周期管理。Invoker是实体域,它是Dubbo的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起invoke调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。

1.ConsumerContextFilter 的invoke 方法

在这里插入图片描述
这里首先对 RpcContext 进行信息设置,其后清空sever上下文,再对调用后的结果进行后处理(即postProcessResult方法,主要设置一些要传递的参数),在finally中清空了传递的参数(目的为下一次调用做准备)。postProcessResult参数中的invoker调用invoke方法会继续调用下一个filter中的invoke方法,即FutureFilter中的invoke方法。从上面过程可以看出主要对 RpcContext 内容进行设置。

2.FutureFilter 的invoke 方法

在这里插入图片描述
主要做一些异步回调工作,其中 invoker.invoke方法会调用MonitorFilter中的invoke方法

3.MonitorFilter中的invoke方法

在这里插入图片描述
MonitorFilter会做下监控的处理。会调用 DubboInvoker中invoke方法。

4.DubboInvoker中invoke方法

在这里插入图片描述
走完上述方法就完成整个方法的调用过程。

猜你喜欢

转载自blog.csdn.net/zhuqiuhui/article/details/84201687