Dubbo源码深度解析(七)

        接上一篇博客《Dubbo源码深度解析(六)》,上篇博客主要从服务消费方开始讲起,主要讲:如果类中的属性或者方法,如果被@DubboReference注解所修饰,Dubbo是怎么处理的,处理逻辑类似Spring框架提供的@Autowired注解。核心就是ReferenceAnnotationBeanPostProcessor类,最终会生成一个对应的ReferenceBean对象,并放入Spring容器,当然最终给属性进行依赖注入的并非ReferenceBean对象,而是它的 ref属性,如果该属性为空,就需要调用Protocol#refer()方法(Dubbo的SPI机制找到Protocol接口的实现类,调用实现类的ref()方法)创建Invoker,最终生成代理对象还没讲到,这篇博客会讲到。然后就是主要讲如何创建Invoker对象,也涉及到从注册中心拉取服务提供方的地址,以及Netty Client是如何跟服务提供方建立连接的逻辑等。

        本篇博客是Dubbo源码讲解的最后一篇,在本篇博客中,会接着上篇的内容继续讲,上篇最后讲到了服务消费方跟服务提供方建立连接,其实讲到这里,Invoker对象的创建也基本讲完了。有一个核心的方法没有讲到,即RegistryProtocol#doCreateInvoker()方法中指向的这一行代码:

7942cdce655b4b46b41965e3b893dc2f.png

        前面也讲到了,这里的cluster对象实际上是MockClusterWrapper对象,而MockClusterWrapper对象的cluster是FailoverCluster对象,看看MockClusterWrapper#join()方法,代码如下:

5d4ba704d43e41c1acca5fcb51eb96a1.png

c97c8d6dd771450389e061e291daf17f.png

        先看看FailoverCluster#doJoin()方法,代码如下:

bbdf8b180c114658a440526e1187337f.png

        再看看AbstractCluster#buildClusterInterceptors()方法,代码如下:

85281aa2585b4973b649e9812830c40f.png        先看看ClusterInterceptor接口,代码如下:

a823d87057484816a6311475ea1a5193.png

        org.apache.dubbo.rpc.cluster.interceptor.ClusterInterceptor文件的内容为:

3fdc294f0ea94025855300e505aefa69.png

        实现类的代码分别是:

332131c6332d42428474e3d9fcf412c0.png

01755f7b80864adcb654b483907ed188.png

        讲ExtensionLoader#getActivateExtension()方法的时候,有一点没有讲到,也就是过滤条件的这个地方:

bbe214c11a99407eac41224f447a5269.png

e2fbe0ed70a34fac9e25472e8a871f76.png

        因此最终获取到的只有ConsumerContextClusterInterceptor对象,最终创建的InterceptorInvokerNode对象的interceptor属性为ConsumerContextClusterInterceptor对象,next属性为FailoverCluster对象。断点验证,结果如下:

754bb6bdb23b4fd0934323dc12c1d0b9.png

        到这里为止,生成Invoker对象的逻辑讲完了。总结一下,最终在ReferenceConfig得到的Invoker是什么样的?或者说是经过了多少层包装?

21d243f2a8f94c65b7026eea480d0940.png

408667afb490480c9689ca6fa94a74cb.png

06ed93d331254511bed33829ba0c80c1.png

3943cb93542f473685bbc3b1a7def96c.png

4b3d5e8b869d415889ee59f745dee9b3.png

32f35f70cca548feb1ddf416d4ab3bdc.png

49565b4724024d7dad3ea04e02a9e941.png

        通过上面这些截图可以知道,最终生成的Invoker对象为:MigrationInvoker对象,而MigrationInvoker对象的invoker属性为MockClusterInvoker对象;而MockClusterInvoker的对象的invoker属性为InterceptorInvokerNode对象;而InterceptorInvokerNode对象interceptor属性为ConsumerContextClusterInterceptor对象,next为FailoverClusterInvoker对象;FailoverClusterInvoker对象里面有个urlInvokerMap属性,key为URL,value为InvokerDelegate对象,而InvokerDelegate的invoker属性为FilterNode对象;而FilterNode对象的filter属性为ConsumerContextFilter属性,它的next属性仍是FilterNode对象;而这个FilterNode对象的filter属性为FutureFilter对象,它的next属性仍是FilterNode对象;这个FilterNode对象的filter属性为MonitorFilter对象,next属性为ListenerInvokerWrapper对象;而ListenerInvokerWrapper对象的invoker属性为AsncToSyncInvoker对象;AsncToSyncInvoker对象的invoker属性为DubboInvoker对象,其中DubboInvoker的clients存放的对象,才是真正跟服务提供方建立连接的客户端(有朋友可能好奇,整理清楚这层层的包装有啥用?用处大了,理顺了才能知道调用链路,也能知道每一层包装的作用是啥,可能其中某一层就做了服务的负债均衡)。断点验证,结果为:

51bf4ca38adc48e1adee01df5ff0d1a6.png        回到ReferenceConfig#createProxy()方法,最终得到的Invoker就是那个上面我讲的,位置为:

376734797e474c6caee7c9152827e391.png

        这里的PROXY_FACTORY属性即为ProxyFactory$Adaptive,即调用ProxyFactory$Adaptive#getProxy()方法,代码如下:

8ab33fa5af6e494bbb6e355fab3a77d5.png

318af42c2fb5454c8c58004b486dc345.png

94e18b8961b944f2a37d2d852c9f4b91.png

        很明显这里的InvokerInvocationHandler实现了InvocationHandler接口,因此在真正执行的是时候,调用的是InvokerInvocationHandler#invoke()方法,断点看看依赖注入的结果:

7badb719ee734c5c95379efb32e85eb3.png

        接下来就是发起远程调用的,即调用HelloService#sayHello()方法,最终调用的是InvokerInvocationHandler#invoke()方法,代码如下:

e2e7df8909a142a0b43f0924b2948a17.png

        有前面讲的可知,InvokerInvocationHandler对象的invoker属性为MigrationInvoker对象,因此直接看MigrationInvoker#invoke()方法,代码如下:

190ec70d4e4c4721a792d7217e493077.png

        看看MigrationInvoker#checkInvokerAvailable()方法,代码如下:

abcd6fac3945407a81da617ec4c3fab9.png

3171e6cddc7744ab92850be6e39ba056.png

811eb5aba37a47dc8dad1db19aff67c4.png

        由于是取反,因此最终调用invoker#invoke()方法,代码如下:

6f97da8aa7f84a1fa4381c40fda0f24c.png

e15147381e354a558b7a383dad7f6fd7.png

0cbb2c84a7d149b5b778d9ec0b39998c.png

        有前面可知,构建的InterceptorInvokerNode链只有一个,而这里的interceptor属性是ConsumerContextClusterInterceptor对象,因此可以看看ConsumerContextClusterInterceptor的before()方法和after()方法,代码如下:

ecc1a7f1e7344a85b4be92b1a379da56.png

        重点看看ClusterInterceptor#intercept()方法,代码如下:

c3dd5f439c244ff6b2df62bf102238c6.png

da1edffe5d754389801e9f24685ad90a.png

        先看看是如何获取Invoker的集合的,看看AbstractClusterInvoker#list()方法,代码如下:

be723f35d34447d79576e85c9dc952e0.png

700b3e58d36c43849027a893532036e5.png

9d3aaf37ab8e4e7786c4227f39d52c45.png

        看看RouterChain#route()方法,代码如下:

ae96f4488e414abc89289d52321f4706.png

        上一篇博客讲到过,此时routers属性中有四个Router对象,顺序分别是:MockInvokersSelector、TagRouter、AppRouter和ServiceRouter。常用的有TagRouter和ConditionRouter,但默认是不加载ConditionRouter的,需要指定。可以通过环境变量来指定,核心方法为:AbstractConfig#refresh()方法,ReferenceBean是其类,看看该方法,代码如下:

6a733f02800843daa39dfebc9041d57a.png

c47f735d71f24c5a80c68d9d03c3d9f8.png

        再看看CompositeConfiguration#getString()方法,传入的当然是解析后的Setter方法的名字,如setRouter() => "router",代码如下:

42f1cc2e60184069bc8cba398301797f.png

d6bb57823d1a42508e1d528b8811e244.png

2b08931a604b427fa80ac2b3309f6a02.png

2cdd1e09fc1647cb826835fba1b1abd2.png

7baee3a227d64f7b8f5e2861aaf388cf.png

        实际上就是在AbstractConfig#refresh()方法中创建的CompositeConfiguration对象,回去看看,代码如下:

33a34eec500f4be9b7716b77c4f37545.png

b09a4bd78799403dbf8b49a6297176bf.png

1ed264cb548f46f49fdc111def89711d.png

        因此可以知道 ,prefix的值为:dubbo.reference.接口全限定名,因此可以这样设置,代码如下:

d131ec5f874e490c9f4fa9eb0507d272.png

        断点验证,结果为:

d4f98cb15d8d4714897210a133810432.png

3080d4c9d3be46b9bab883d285ce97d9.png

        当然,还可以用Dubbo的配置文件,即dubbo.properties,如下:

c3ede789ebdb4e5cb61ea50f8f324e9b.png

ef7382a5982b428abf222865eda6063a.png

ee4aa0905dd54866a4a796321291c577.png

98829c9effee4d858dd59113c9d6fa71.png

033815b27af5461ab49944790bdaa9f2.png

        当然也可以通过@DubboReference注解指定,由于注解中没有直接提供 router属性,因此需要这样指定:

fd5b27ba91b94b7380a4b5f96d51899d.png

        处理@DubboReference注解的parameters属性的代码在这里:

772fcbcb19b54d1abc630c44eee28c2c.png

1f7bf4fee45d4ecc90a4373ec162eecf.png

f1387458c1464f9e9da390fb78d6d04e.png

        回到之前说的,主要看TagRouter和ConditionRouter的使用方法。先说TagRouter,这是给服务消费方和服务提供方发打上标签,只有服务消费方的tag和服务提供方的tag一直才能调用,前置准备,先是服务提供方配置:

83f6eaf4152b4e77bf6e815b9153c6d2.png

a549aedc000847bba42e94eb470de879.png

        启动服务提供方服务,再在做如下修改:

c230d03d3a714c52842361784330f017.png

0a5652eeab7c49688d7701b637b04f25.png

daa3bfdd1087410282f71493089f3cf3.png

        再次启动服务提供方的服务,再看看Nacos,结果如下:

95fe0816bceb4716bc12dd4cbf378266.png

22d21a22c736474690b9a6b0d56514c4.png

        再配置服务消费方,配置如下:

330f5d9d4e9a4de3964e6b7a322429f2.png

        启动服务消费方服务,直接看RegistryDirectory#doList()方法,并打断点,结果如下:

c3d8d4a82c5b4a02a41b451a8eed6638.png

ac96bbe92c3e4496a8089cf833c54610.png

02243d7632ae4508bca139fa259d84c4.png

002cdfb977144110a3e0e6591c18d0eb.png

    未完待续(明天继续完善本篇博客)

        

        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/51971.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

tomcat相关

一、部署安装tomcat 在10和20上安装tomcat [root10 ~]# dnf install java-1.8.0-openjdk.x86_64 -y #安装java环境 [root10 ~]# tar zxf apache-tomcat-9.0.93.tar.gz -C /usr/local/ #安装并启动tomcat [root10 ~]# ln -s /usr/local/apache-tomcat-9.0.93/ /usr/local/tomcat…

NC 完全二叉树结点数

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 描述 给定一棵完全…

社交巨头的下一步:Facebook的未来发展方向

作为全球最大的社交媒体平台之一,Facebook(现Meta)一直在不断推动其平台的技术创新和战略调整,以适应不断变化的市场需求和用户期望。随着技术的进步和社交媒体环境的演变,Facebook的未来发展方向正在显现出新的趋势和…

DC-DC 转换器中的压电谐振器:当前状态和限制

在小体积和高频下提高功率密度并减小电感器和变压器的尺寸是DC-DC转换器设计中的一大挑战。为了克服这些困难,压电谐振器(PR)通过利用潜在的压电效应,以振动模式而不是电模式存储能量。 即使 PR 的使用在效率和功率密度方面改进了…

轻松创作高质量的AI音乐——Suno API

Suno 歌曲生成 API 对接指南 随着人工智能技术的飞速发展,各类 AI 程序已如雨后春笋般涌现。AI 不再是遥不可及的存在,它的身影深入了人类工作与生活的每一个角落。其应用领域也愈加广泛,从初期的写作,到现如今的医疗、教育&…

【数据结构-距离和】力扣2602. 使数组元素全部相等的最少操作次数

给你一个正整数数组 nums 。 同时给你一个长度为 m 的整数数组 queries 。第 i 个查询中,你需要将 nums 中所有元素变成 queries[i] 。你可以执行以下操作 任意 次: 将数组里一个元素 增大 或者 减小 1 。 请你返回一个长度为 m 的数组 answer &#x…

WUP-MY-LABEL-PRINTER 旻佑热敏打印机标签打印uniapp插件使用说明

插件地址:WUP-MY-LABEL-PRINTER 旻佑热敏打印机标签打印安卓库 简介 本插件主要用于旻佑热敏打印机打印标签,不支持票据打印。适用于旻佑的各型支持标签打印的热敏打印机。本插件开发时使用的打印机型号为MY-805嵌入式面板打印机,其他型号请…

C的动态内存管理 free()和malloc()的简单实现——free()根据内存地址便知释放内存的空间大小(原理详解)

malloc与free malloc 分配的内存是未初始化的,其中的字节内容是不确定的(可能是随机值)。 如果内存分配失败,malloc 返回一个空指针 NULL,可以通过检查返回值来判断是否分配成功。 void* malloc (size_t size); cal…

Linux压缩和解压

目录 压缩和解压类 gzip/gunzip指令 zip/unzip指令 tar指令 压缩和解压类 gzip/gunzip指令 gzip用于压缩文件,gunzip用于解压缩文件。 解压后去掉了gz的后缀。 zip/unzip指令 ​​​​​​​ 将文件压缩后发给别人,别人再解压。 将整个文件压…

上千条备孕至育儿指南速查ACCESS\EXCEL数据库

虽然今天这个数据库的记录数才不过区区上千条,但是每条记录里的内容都包含四五个子标题,可以将相关的知识完整且整齐的展现,是个属于简而精的数据库。并且它包含2级分类。 【备孕】大类包含:备孕百科(19)、不孕不育(23)、精子卵子…

uniapp 微信小程序生成水印图片

效果 源码 <template><view style"overflow: hidden;"><camera device-position"back" flash"auto" class"camera"><cover-view class"text-white padding water-mark"><cover-view class"…

165万人在线《黑神话:悟空》登顶STEAM!勾起太多回忆,我冲啦!

本公众号由以下老铁赞助&#xff0c;感谢他们❗️ 2024年8月20日&#xff0c;一个平凡而又特殊的日子&#xff0c;国产游戏《黑神话&#xff1a;悟空》正式上线 Steam平台&#xff0c;在线人数突破165万&#xff0c;超越《反恐精英CS2》登顶热玩榜。 更牛逼的是 Steam 热玩排行…

滚雪球学Java(87):Java事务处理:JDBC的ACID属性与实战技巧!真有两下子!

咦咦咦&#xff0c;各位小可爱&#xff0c;我是你们的好伙伴——bug菌&#xff0c;今天又来给大家普及Java SE啦&#xff0c;别躲起来啊&#xff0c;听我讲干货还不快点赞&#xff0c;赞多了我就有动力讲得更嗨啦&#xff01;所以呀&#xff0c;养成先点赞后阅读的好习惯&#…

Kafka快速入门:Kafka驱动JavaApi的使用

生产者和消费者是Kafka的核心概念之一&#xff0c;它们在客户端被创建和使用&#xff0c;并且包含了许多与Kafka性能和机制相关的配置。虽然Kafka提供的命令行工具能够执行许多基本操作&#xff0c;但它无法实现所有可能的性能优化。相比之下&#xff0c;使用Java API可以充分利…

打造更高效的项目:如何选择合适的管理工具

国内外主流的 10 款项目工程管理系统对比&#xff1a;PingCode、Worktile、Asana、Trello、Monday.com、ClickUp、Wrike、泛微项目协同工具、广联达项目管理软件、泛普OA。 在选择项目工程管理系统时&#xff0c;你是否经常感到无从下手&#xff0c;担心投资不当或工具不适合自…

Python 使用 matplotlib 显示图像

如果没有安装 matplotlib 需要先安装&#xff1a; pip install matplotlib一、读取图片并显示 import matplotlib.pyplot as pltimage_path "/Users/AlanWang4523/Desktop/Debug/files/image.png" image_array plt.imread(image_path)plt.figure("ImageShow…

[数据集][目标检测]停车场空位检测数据集VOC+YOLO格式7959张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;7959 标注数量(xml文件个数)&#xff1a;7959 标注数量(txt文件个数)&#xff1a;7959 标注…

【保姆级教程】5分钟上手 Coze 自建插件,把 AI 接入个人微信

上篇&#xff0c;给大家介绍了一款搭建微信机器人的开源项目&#xff1a; 搭建微信机器人的第4种方式&#xff0c;我造了一个摸鱼小助手 不同于需要付费的项目&#xff0c;它的定制化程度非常高~ 问题来了&#xff1a;怎么接入 AI 能力呢&#xff1f; 考虑到大家对 Coze 智能…

AI 智能体:从普通人到《黑神话:悟空》,保姆级教程让你瞬间变身!

大家好&#xff0c;我是木川 今天还没下班&#xff0c;就看到一款名为《黑神话:悟空》的游戏火爆全网&#xff0c;唤醒了无数玩家对大圣孙悟空的崇拜与向往。游戏中&#xff0c;悟空的七十二变让人叹为观止&#xff0c;但你是否想过&#xff0c;借助AI的力量&#xff0c;我们也…

实验十 编写子程序《汇编语言》- 王爽

一. 显示字符串 1. 需求 显示字符串是现实工作中经常要用到的功能&#xff0c;应该编写一个通用的子程序来实现这个功能。我们应该提供灵活的调用接口&#xff0c;使用者可以决定显示的位置&#xff08;行、列&#xff09;、内容和颜色。 子程序描述 名称&#xff1a;show_str…