本文对应源码地址:https://github.com/nieandsun/dubbo-study


文章目录

  • 1 dubbo中Invoker的重要性
  • 2 dubbo RPC链条中代理对象的底层逻辑
    • 2.1 以之前的文章为基础实现一个简单的dubbo服务端+消费端
    • 2.2 代理对象的底层逻辑
    • 2.3 跳过代理对象利用直接构造的RpcInvocation对象拉通整个RPC链条
  • 3 dubbo中Invoker嵌套调用底层原理
  • 4 dubbo的RPC调用简图最终效果

1 dubbo中Invoker的重要性

上篇文章《【dubbo源码解析】— dubbo的服务注册与发现机制底层原理探析》讲解到在不加入注册中心逻辑之前,dubbo中消费端@Reference注解标注的bean进行方法调用的过程如下图所示:

假如你clone下来我上篇文章对应的代码,并跟了一下源码的话,那你肯定知道在引入注册中心后:

  • (1)其实在服务端 RegistryProtocol对象将Invoker交给具体的Protocol进行服务暴露时,传入的并不是原始的Invoker,而是将其包装成了一个InvokerDelegete对象(也是一个Invoker)

则当服务端被调用时,其实是先调用到这个InvokerDelegete对象的invoke方法—>然后再在InvokerDelegete对象内部调用原始Invoker的invoke方法 —> 最后才真正调用的ref对象的具体方法

  • (2)而在消费端其实也不是一下就由具体的Protocol获取到【可以调用远程服务的对象】,然后将其和【url】【interface】封装为一个Invoker。 其实在消费端也是在最外层包了一个XXXClusterInvoker。

也就是说在消费端@Reference注解标注的bean进行方法调用时,会先调用XXXClusterInvoker的invoke方法—》然后再调用由具体的Protocol获取到包装了【可以调用远程服务的对象】的Invoker的invoke方法 —》然后调用远程服务。

实际上我们真实dubbo开发中遇到的过滤器链负载均衡容错等组件的底层逻辑的具体实现都被封装成了一个个Invoker对象,串联在dubbo的整个RPC链条中 , 画个dubbo的RPC调用简图大致如下:

由此可知在dubbo中Invoker对象,非常重要!!!


2 dubbo RPC链条中代理对象的底层逻辑


2.1 以之前的文章为基础实现一个简单的dubbo服务端+消费端

如果看过前面几篇文章的话,相信对于下面的代码你肯定不会陌生:
服务端

Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
//代理
ProxyFactory proxy = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();//注册中心服务--zk
final URL registryUrl = URL.valueOf("registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?registry=zookeeper");//支持的协议:dubbo,http,hessian,rmi
URL serviceUrl = URL.valueOf("rmi://127.0.0.1:9001/com.nrsc.service.InvokerDemoService" + "?proxy=jdk"); //动态代理@Test
public void serverRpc() throws IOException {InvokerDemoService service = new InvokerDemoServiceImpl("yoyo");serviceUrl = serviceUrl.setPort(9001);URL newRegistryUrl = registryUrl.addParameter(Constants.EXPORT_KEY, serviceUrl.toFullString());//暴露服务Invoker<InvokerDemoService> serviceInvoker = proxy.getInvoker(service, InvokerDemoService.class, newRegistryUrl);Exporter<InvokerDemoService> exporter = protocol.export(serviceInvoker);System.out.println("server 启动协议:" + serviceUrl.getProtocol());// 保证服务一直开着System.in.read();exporter.unexport();
}

消费端

@Test
public void clientRpc() {Invoker<InvokerDemoService> referInvoker = protocol.refer(InvokerDemoService.class, registryUrl);//获取【可以调用远程服务的对象】的代理对象,当调用此对象的方法时会走代理逻辑,调用referInvoker的invoke方法InvokerDemoService service = proxy.getProxy(referInvoker);String result = service.sayHello(registryUrl.getProtocol() + "调用");System.out.println(result);
}

2.2 代理对象的底层逻辑

上面的代码消费端和服务端肯定是可以调通的,这里有兴趣的可以自己测试一下。但是下面的这行代码的底层逻辑究竟是什么呢?

String result = service.sayHello(registryUrl.getProtocol() + "调用");

其实它底层的逻辑,我在《【dubbo源码解析】— dubbo的服务暴露+服务消费(RPC调用)底层原理深入探析》这篇文章里讲过。以动态代理为例,当使用代理对象service调用方法时,它会走InvokerInvocationHandler中的invoke方法(动态代理的逻辑) —> 然后在该方法里调用Invoker的invoke方法,其源码如下:

public class InvokerInvocationHandler implements InvocationHandler {private final Invoker<?> invoker;public InvokerInvocationHandler(Invoker<?> handler) {this.invoker = handler;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String methodName = method.getName();Class<?>[] parameterTypes = method.getParameterTypes();if (method.getDeclaringClass() == Object.class) {return method.invoke(invoker, args);}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]);}//调用Invoker的invoke方法return invoker.invoke(new RpcInvocation(method, args)).recreate();}
}

这里可以注意到,其实它底层就是将service调用的方法(method)和具体的参数(args)封装成一个RpcInvocation对象,然后拿着这个封装的参数来调用Invoker的invoke方法(再底层又用到了反射,有兴趣的可以看一下,挺简单的)。

实际上这个RpcInvocation对象的构建不仅可以使用method和args,它还有如下构造方法

由此可知我们其实可以直接构建一个RpcInvocation对象,然后拿着它直接调用Invoker的invoke方法,来直接拉通整个dubbo的RPC调用流程 。


2.3 跳过代理对象利用直接构造的RpcInvocation对象拉通整个RPC链条

以上图中黄色箭头指定的构造方法构造RpcInvocation对象,并进行消费端调用的demo:

@Test
public void clientInvoker() {Invoker<InvokerDemoService> referInvoker = protocol.refer(InvokerDemoService.class, registryUrl);//直接构造RpcInvocation对象Invocation invocation = new RpcInvocation("sayHello", new Class<?>[]{String.class}, new Object[]{"invoke直接调用"}, null);//拿着构造的RpcInvocation对象直接调用referInvoker的invoke方法Result result2 = referInvoker.invoke(invocation);System.out.println(result2.getValue());
}

测试结果如下:


3 dubbo中Invoker嵌套调用底层原理

dubbo中Invoker的嵌套调用底层原理基本如下 —过滤器链负载均衡容错机制等其底层逻辑都是按照下面的逻辑被封装嵌套到dubbo的整个RPC链条中。

这里简单提供一个dubbo的Invoker嵌套调用示例:

private Invocation invocation = new RpcInvocation("sayHello", new Class<?>[]{String.class}, new Object[]{"invoke调用"}, null);@Test
public void clientInvokerWrapper() throws IOException {//获取包装了【可以调用远程服务的对象】的InvokerInvoker<InvokerDemoService> referInvoker = protocol.refer(InvokerDemoService.class, registryUrl);//对包装了【可以调用远程服务的对象】的Invoker再嵌套一个InvokerInvoker<InvokerDemoService> wrapperInvoker = new Invoker<InvokerDemoService>() {private Invoker<InvokerDemoService> invoker = referInvoker;@Overridepublic Class<InvokerDemoService> getInterface() {return invoker.getInterface();}@Overridepublic Result invoke(Invocation invocation) throws RpcException {System.out.println("invoker嵌套调用");return invoker.invoke(invocation);}@Overridepublic URL getUrl() {return invoker.getUrl();}@Overridepublic boolean isAvailable() {return false;}@Overridepublic void destroy() {}};//拿着invocation调用最外层Invoker的invoke方法,由于最外层的Invoker里有包装了【可以调用远程服务的对象】的Invoker,//所以可以现在最外层的Invoker的invoke方法里先做些事情再调用包装了【可以调用远程服务的对象】的Invoker的invoke方法Result result3 = wrapperInvoker.invoke(invocation);System.out.println(result3.getValue());
}

简单看一下测试结果:


4 dubbo的RPC调用简图最终效果


end!

【dubbo源码解析】--- dubbo中Invoker嵌套调用底层原理相关推荐

  1. Dubbo源码解析-Dubbo服务消费者_Dubbo协议(一)

    前言: 在介绍完Dubbo 本地模式(Injvm协议)下的服务提供与消费后,上文我们又介绍了Dubbo远程模式(dubbo协议)下的服务暴露过程,本质上就是通过Netty将dubbo协议端口暴露出去, ...

  2. Dubbo源码解析 —— Router

    作者:肥朝 原文地址:http://www.jianshu.com/p/278e782eef85 友情提示:欢迎关注公众号[芋道源码].????关注后,拉你进[源码圈]微信群和[肥朝]搞基嗨皮. 友情 ...

  3. Dubbo源码解析 --- DIRECTORY和ROUTER

    Dubbo源码解析 --- DIRECTORY和ROUTER 今天看一下Directory和Router. 我们直接从代码看起(一贯风格),先看后总结,对着总结再来看,相信会收获很多.我们先看com. ...

  4. dubbo源码解析-集群容错架构设计

    前言 本来是想把整个dubbo源码解析一次性弄完,再做成一个系列来发布的,但是正巧最近有位好朋友要去杭州面试,就和我交流了一下.本着对dubbo源码略有心得的心态,在交流过程中也发表了个人的一些粗劣的 ...

  5. dubbo源码解析(二)

    大家好,我是烤鸭: dubbo 源码解析: 1.服务导出 介绍: Dubbo 服务导出过程始于 Spring 容器发布刷新事件,Dubbo 在接收到事件后,会立即执行服务导出逻辑.整个逻辑大致可分为三 ...

  6. dubbo(5) Dubbo源码解析之服务调用过程

    来源:https://juejin.im/post/5ca4a1286fb9a05e731fc042 Dubbo源码解析之服务调用过程 简介 在前面的文章中,我们分析了 Dubbo SPI.服务导出与 ...

  7. dubbo源码解析-逻辑层设计之服务降级

    Dubbo源码解析系列文章均来自肥朝简书 前言 在dubbo服务暴露系列完结之后,按计划来说是应该要开启dubbo服务引用的讲解.但是现在到了年尾,一些朋友也和我谈起了明年跳槽的事.跳槽这件事,无非也 ...

  8. dubbo源码解析之框架粗谈

    dubbo框架设计 一.dubbo框架整体设计 二.各层说明 三.dubbo工程模块分包 四.依赖关系 五.调用链 文章系列 [一.dubbo源码解析之框架粗谈] [二.dubbo源码解析之dubbo ...

  9. Dubbo源码解析 - 远程暴露

    作者:肥朝 原文地址:http://www.jianshu.com/p/893f7e6e0c58 友情提示:欢迎关注公众号[芋道源码].????关注后,拉你进[源码圈]微信群和[肥朝]搞基嗨皮. 友情 ...

最新文章

  1. 第十五届全国大学生智能汽车竞赛竞速赛规则(讨论稿)
  2. Android studio 另一个程序正在使用此文件,进程无法访问
  3. 1.2.1 计算机系统的组成(硬件+软件)
  4. 计算机控制试卷中南大学,期末试卷,需要的自取
  5. 最小栈—leetcode155
  6. C#连接Excel和Access(包括2003和2007版)方法总结
  7. 例子:好友列表选中效果
  8. System.Convert 的一些事
  9. 用友u8采购发票如何取消审核
  10. 04. 替换空格(C++版本)
  11. Python根据mask在原图上进行标记
  12. java 的.class 反编译软件
  13. vcpkg Ubuntu安装
  14. Python 并发简介(多线程、多进程)
  15. 脚本c语言编程实例,AVR C语言编程通用脚本.doc
  16. 国内硕士申请加拿大计算机博士难度,【经验分享】如何申请加拿大硕士研究生或者博士?...
  17. python3 extract_model.py对应代码解读抽取式提取+生成式提取摘要代码解读------摘要代码解读3
  18. html5版堆糖,堆糖(Duitang)
  19. mysql 引擎 切换_Mysql表引擎的切换
  20. Java之原子性-乐观锁与悲观锁

热门文章

  1. 基于飞思卡尔NXP的MKE02单片机的俄罗斯方块KEIL5平台C代码可移植显示成绩
  2. 如何在网页中实现音乐播放功能
  3. ESP8266-Arduino编程实例-PCF8574IO扩展模块驱动
  4. 新手学Python一定很疑惑自学Python入门要买什么书容易上手?
  5. golang excel导出 style样式和所有流程
  6. Canny边缘检测算法(C++实现)
  7. 论文格式及小论文写法
  8. 免费在线服务器架构图制作
  9. 五分钟学GIS | 倾斜摄影单体化技术
  10. 大数据工具:IKAnalyzer分词工具介绍与使用