【dubbo源码解析】--- dubbo中Invoker嵌套调用底层原理
本文对应源码地址: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嵌套调用底层原理相关推荐
- Dubbo源码解析-Dubbo服务消费者_Dubbo协议(一)
前言: 在介绍完Dubbo 本地模式(Injvm协议)下的服务提供与消费后,上文我们又介绍了Dubbo远程模式(dubbo协议)下的服务暴露过程,本质上就是通过Netty将dubbo协议端口暴露出去, ...
- Dubbo源码解析 —— Router
作者:肥朝 原文地址:http://www.jianshu.com/p/278e782eef85 友情提示:欢迎关注公众号[芋道源码].????关注后,拉你进[源码圈]微信群和[肥朝]搞基嗨皮. 友情 ...
- Dubbo源码解析 --- DIRECTORY和ROUTER
Dubbo源码解析 --- DIRECTORY和ROUTER 今天看一下Directory和Router. 我们直接从代码看起(一贯风格),先看后总结,对着总结再来看,相信会收获很多.我们先看com. ...
- dubbo源码解析-集群容错架构设计
前言 本来是想把整个dubbo源码解析一次性弄完,再做成一个系列来发布的,但是正巧最近有位好朋友要去杭州面试,就和我交流了一下.本着对dubbo源码略有心得的心态,在交流过程中也发表了个人的一些粗劣的 ...
- dubbo源码解析(二)
大家好,我是烤鸭: dubbo 源码解析: 1.服务导出 介绍: Dubbo 服务导出过程始于 Spring 容器发布刷新事件,Dubbo 在接收到事件后,会立即执行服务导出逻辑.整个逻辑大致可分为三 ...
- dubbo(5) Dubbo源码解析之服务调用过程
来源:https://juejin.im/post/5ca4a1286fb9a05e731fc042 Dubbo源码解析之服务调用过程 简介 在前面的文章中,我们分析了 Dubbo SPI.服务导出与 ...
- dubbo源码解析-逻辑层设计之服务降级
Dubbo源码解析系列文章均来自肥朝简书 前言 在dubbo服务暴露系列完结之后,按计划来说是应该要开启dubbo服务引用的讲解.但是现在到了年尾,一些朋友也和我谈起了明年跳槽的事.跳槽这件事,无非也 ...
- dubbo源码解析之框架粗谈
dubbo框架设计 一.dubbo框架整体设计 二.各层说明 三.dubbo工程模块分包 四.依赖关系 五.调用链 文章系列 [一.dubbo源码解析之框架粗谈] [二.dubbo源码解析之dubbo ...
- Dubbo源码解析 - 远程暴露
作者:肥朝 原文地址:http://www.jianshu.com/p/893f7e6e0c58 友情提示:欢迎关注公众号[芋道源码].????关注后,拉你进[源码圈]微信群和[肥朝]搞基嗨皮. 友情 ...
最新文章
- 第十五届全国大学生智能汽车竞赛竞速赛规则(讨论稿)
- Android studio 另一个程序正在使用此文件,进程无法访问
- 1.2.1 计算机系统的组成(硬件+软件)
- 计算机控制试卷中南大学,期末试卷,需要的自取
- 最小栈—leetcode155
- C#连接Excel和Access(包括2003和2007版)方法总结
- 例子:好友列表选中效果
- System.Convert 的一些事
- 用友u8采购发票如何取消审核
- 04. 替换空格(C++版本)
- Python根据mask在原图上进行标记
- java 的.class 反编译软件
- vcpkg Ubuntu安装
- Python 并发简介(多线程、多进程)
- 脚本c语言编程实例,AVR C语言编程通用脚本.doc
- 国内硕士申请加拿大计算机博士难度,【经验分享】如何申请加拿大硕士研究生或者博士?...
- python3 extract_model.py对应代码解读抽取式提取+生成式提取摘要代码解读------摘要代码解读3
- html5版堆糖,堆糖(Duitang)
- mysql 引擎 切换_Mysql表引擎的切换
- Java之原子性-乐观锁与悲观锁