Dubbo源码深度解析(七)

news2024/11/15 18:20:12

        接上一篇博客《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.coloradmin.cn/o/2057617.html

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

相关文章

JavaScript - Ajax

Asynchronous JavaScript And XML,异步的JavaScript和XML 作用: 数据交换:通过Ajax可以给服务器发送请求,并获取服务器响应的数据。异步交互:可以在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术…

Vue2 与 Vue3 生命周期对比

首先我们需要了解 Vue2 的生命周期,请参考我之前写的博文 Vue2-生命周期 Vue2 生命周期存在四个阶段,八个钩子函数,具体作用可以看图,详细解释可以参考之前的博文 Vue3 生命周期 经过对比,我们发现 Vue3 的生命周期也存…

Office办公软件从哪里下载

Offece下载方法有哪些?从哪里下载Office办公软件?是日常办公必不可少的常用软件。 进入正题 第一步:下载最新的office办公软件软件包 https://docs.qq.com/doc/DQUhtSnJxU1FxZnVF 先下载后解压,看到下面的文件 然后右击-以管理…

mq-work模型

work模型是什么-任务模型 会产生什么现象? 操作 1、新建一个队列 2、在consuner增加2个消费者 2、发送50条消息 4、消费者1和消费者2,一轮1次 消费能力不一致,还是一人一个消费50条消息,所以浪费了能力 总结 prefetch预获取&#…

文心快码 Baidu Comate 前端工程师观点分享:以文心快码 Baidu Comate为例,智能代码助手需要什么(一)

本系列视频来自百度工程效能部的前端研发经理杨经纬,她在由开源中国主办的“AI编程革新研发效能”OSC源创会杭州站105期线下沙龙活动上,从一款文心快码(Baidu Comate)前端工程师的角度,分享了关于智能研发工具本身的研…

单片机原理及技术(六)—— 中断系统的工作原理

目录 一、AT89S51中断技术概述 二、AT89S51中断系统结构 2.1 中断请求源 2.2 中断请求标志寄存器 2.2.1 TCON 寄存器 2.2.2 SCON 寄存器 三、中断允许与中断优先级的控制 3.1 中断允许寄存器 IE 3.2 中断优先级寄存器 IP 四、响应中断请求的条件 五、外部中断的触发…

KubeSphere核心实战_kubesphere部署redis02_创建redis现指定存储卷_配置外网访问服务---分布式云原生部署架构搭建048

然后我们再去看一下服务,这里,这里就是刚刚我们创建 redis工作负载的时候,给咱们自动生成了一个服务,可以看到这个服务, his-redis-后面有乱码是自动生成的,如果我们想弄一个有意义的,好看的,可以删除了自己创建 比如我们删除掉自动生成的服务,注意不要删除工作负载 点击确定…

文书智能助手

背景 司法、医疗等行业存在着大量的文书,一份文书或者卷宗少则几十页,多则几万页。在查看和检查这些文书时,会遇到大量的信息。当需要查询进一步的详细内容时,往往需要选择一下文字,然后再在各种系统中 查询详细的信息…

ES与MySQL数据同步实现方式

1.什么是数据同步: 1.Elasticsearch中的酒店数据来自于mysql数据库,因此mysql数据发生改变时,Elasticsearch也必须跟着改变,这个就是Elasticsearch与mysql之间的数据同步 2.数据同步实现方式: 常见的数据同步方案有三种&#x…

2020 位示图

假设某计算机的字长为32位,该计算机文件管理系统磁盘空间管理采用位示图(bitmap),记录磁盘的使用情况。若磁盘的容量为300GB,物理块的大小为4MB,那 么位示图的大小为( )个字。 要计…

【SQL】仅出现一次的最大数据

目录 题目 分析 代码 题目 MyNumbers 表: ------------------- | Column Name | Type | ------------------- | num | int | ------------------- 该表可能包含重复项(换句话说,在SQL中,该表没有主键)。…

一个轻量级的数据库条件检索引擎,专门设计来简化后端查询逻辑的开发,专注高级查询的只读 ORM 工具(附源码)

前言 在软件开发过程中,后端开发者经常面临着复杂多变的数据库查询需求。产品经理和项目经理可能会频繁地提出新的查询条件,要求支持各种模糊查询、直接查询,甚至需要在用户界面上提供下拉列表等元素,以增强用户体验。 然而&…

进阶SpringBoot之 Druid 数据源

Druid 是开源平台上一个数据库连接池实现&#xff0c;具备日志监控功能 Druid 可以很好的监控 DB 连接池和 SQL 的执行情况&#xff0c;天生就是针对监控而生的 DB 连接池 Maven 仓库 pom.xml 文件导入 Durid 的 jar 包 <!-- Druid依赖 --><dependency><grou…

前端视角解决chrome/firefox浏览器访问国家税务局发票查验平台验证码获取提示”网络异常,请稍后再试“解决方法

目录 问题描述问题原因解决办法 问题描述 chrome等浏览器访问国家税务局发票查验平台时获取验证码提示”网络异常&#xff0c;请稍后再试“&#xff0c;安装根证书、信任根证书也无效 问题原因 使用开发者工具查看执行过程&#xff0c;点击获取验证码后ajax请求地方税务局的…

嵌入式AI快速入门课程-K510篇 (一)

嵌入式AI快速入门课程-K510篇 手册属性 属性描述类别嵌入式AI开发文档名嵌入式AI快速入门手册-K510篇当前版本1.0适用型号DongshanPI-Vision编辑百问科技文档编辑团队审核韦东山 更新记录 更新日期更新内容更新版本2023/11/09文档大纲编写完毕V1.0 文章目录 嵌入式AI快速入门课…

如何培养单元测试的习惯?怎样才算一个好的单元测试?

你是怎么编写单元测试的呢&#xff1f;很多人的做法是先把所有的功能代码都写完&#xff0c;然后&#xff0c;再针对写好的代码一点一点地补写测试。 在这种编写测试的做法中&#xff0c;单元测试扮演着非常不受人待见的角色。你的整个功能代码都写完了&#xff0c;再去写测试…

C语言:顺序表的实现和通迅录项目实现

顺序表 1、顺序表的概念及结构 1.1 线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是⼀种在实际中⼴泛使⽤的数据结构&#xff0c;常⻅的线性表&#xff1a;顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构&…

openstack基本操作

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

python语言day9 正则表达式 和 xpath 解析html

正则表达式&#xff1a; 正则表达式的语法&#xff1a; 元字符&#xff1a; \D \d \w \W . [ ] 量词&#xff1a; ? * 惰性匹配&#xff1a; 玩儿(?P<name>.*?)游戏&#xff1a; 匹配到第一个游戏结束&#xff0c;name 匹配的文本。 玩儿(?P<na…

分享cesium的风场开源网站

首先是有在二维地图上的一个风场效果&#xff0c;通过canvas进行的绘制&#xff0c;例如leaflet开源地图上就能够根据数据生成风场的效果图。 最近mapbox里的大神分享了如何在cesium上实现风场的效果&#xff0c;并在github上进行了开源&#xff0c;开源地址: https://github.…