dubbo protocol port 消费者端_Dubbo源码:搞定URL,就走完了进度条的一半

4722ac7707fe97e0fef06aa9729fa434.png

Dubbo 中的 URL

大家都知道,在互联网领域,每个信息资源都有统一的且在网上唯一的地址,该地址就叫 URL(Uniform Resource Locator,统一资源定位符),它是互联网的统一资源定位标志,也就是指网络地址。

bb59ceeddaa7436577c843208b8ec7a8.png

Dubbo 中任意的一个实现都可以抽象为一个 URL,Dubbo 使用 URL 来统一描述了所有对象和配置信息,并贯穿在整个 Dubbo 框架之中。

dubbo://172.17.32.91:20880/org.apache.dubbo.demo.DemoService?anyhost=true&application=dubbo-demo-api-provider&dubbo=2.0.2&interface=org.apache.dubbo.demo.DemoService&methods=sayHello,sayHelloAsync&pid=32508&release=&side=provider&timestamp=1593253404714dubbo://172.17.32.91:20880/org.apache.dubbo.demo.DemoService?anyhost=true&application=dubbo-demo-api-provider&dubbo=2.0.2&interface=org.apache.dubbo.demo.DemoService&methods=sayHello,sayHelloAsync&pid=32508&release=&side=provider&timestamp=1593253404714

这个 Demo Provider 注册到 ZooKeeper 上的 URL 信息,简单解析一下这个 URL 的各个部分:

  • protocol:dubbo 协议
  • username/password:没有用户名和密码
  • host/port:172.17.32.91:20880
  • path:org.apache.dubbo.demo.DemoService
  • parameters:参数键值对,这里是问号后面的参数

下面是 URL 的构造方法:

public URL(String protocol,             String username,             String password,             String host,             int port,             String path,             Map<String, String> parameters,             Map<String, Map<String, String>> methodParameters) {     if (StringUtils.isEmpty(username)             && StringUtils.isNotEmpty(password)) {         throw new IllegalArgumentException("Invalid url");     }     this.protocol = protocol;     this.username = username;     this.password = password;     this.host = host;     this.port = Math.max(port, 0);     this.address = getAddress(this.host, this.port);     while (path != null && path.startsWith("/")) {         path = path.substring(1);     }     this.path = path;     if (parameters == null) {         parameters = new HashMap<>();     } else {         parameters = new HashMap<>(parameters);     }     this.parameters = Collections.unmodifiableMap(parameters);     this.methodParameters = Collections.unmodifiableMap(methodParameters); }

另外,在 dubbo-common 包中还提供了 URL 的辅助类:

  • URLBuilder, 辅助构造 URL
  • URLStrParser, 将字符串解析成 URL 对象

19eb46ba179dcb8f07cf0dc01da3d702.png

URL 在 Dubbo 中被当作是“公共的契约”。一个 URL 可以包含非常多的扩展点参数,URL 作为上下文信息贯穿整个扩展点设计体系。

其实在 Dubbo 中使用 URL 的好处多多:

  • 代码更加易读、易懂,不用花大量时间去揣测传递数据的格式和含义,进而形成一个统一的规范
  • 作为方法的入参(相当于一个 Key/Value 都是 String 的 Map),含义比单个参数更丰富,当代码需要扩展的时候,可以将新的参数以 Key/Value 的形式追加到 URL 之中,而不需要改变入参或是返回值的结构
  • 可以省去很多沟通成本

URL 在 SPI 中的应用

Dubbo SPI 中有一个依赖 URL 的重要场景——适配器方法,是被 @Adaptive 注解标注的, URL 一个很重要的作用就是与 @Adaptive 注解一起选择合适的扩展实现类。

例如,在 dubbo-registry-api 模块中我们可以看到 RegistryFactory 这个接口,其中的 getRegistry() 方法上有 @Adaptive({"protocol"}) 注解,说明这是一个适配器方法,Dubbo 在运行时会为其动态生成相应的 “$Adaptive” 类型,如下所示:

public class RegistryFactory$Adaptive              implements RegistryFactory {     public Registry getRegistry(org.apache.dubbo.common.URL arg0) {         if (arg0 == null) throw new IllegalArgumentException("...");         org.apache.dubbo.common.URL url = arg0;         // 尝试获取URL的Protocol,如果Protocol为空,则使用默认值"dubbo"         String extName = (url.getProtocol() == null ? "dubbo" :              url.getProtocol());         if (extName == null)             throw new IllegalStateException("...");         // 根据扩展名选择相应的扩展实现,Dubbo SPI的核心原理在下一课时深入分析         RegistryFactory extension = (RegistryFactory) ExtensionLoader           .getExtensionLoader(RegistryFactory.class)                 .getExtension(extName);         return extension.getRegistry(arg0);     } }

我们会看到,在生成的 RegistryFactory$Adaptive 类中会自动实现 getRegistry() 方法,其中会根据 URL 的 Protocol 确定扩展名称,从而确定使用的具体扩展实现类。

我们可以找到 RegistryProtocol 这个类,并在其 getRegistry() 方法中打一个断点, 得到如下图所示的内容:

2c6f5c3b8263b035271fb32595bc683d.png

这里传入的 registryUrl 值为:

zookeeper://127.0.0.1:2181/org.apache.dubbo...

那么在 RegistryFactory$Adaptive 中得到的扩展名称为 zookeeper,此次使用的 Registry 扩展实现类就是 ZookeeperRegistryFactory。

URL 在服务暴露中的应用

Provider 在启动时,会将自身暴露的服务注册到 ZooKeeper 上,来看 ZookeeperRegistry.doRegister() 方法,在其中打个断点,然后 Debug 启动 Provider,会得到下图:

57cafa484946dc3dcf32b23153118ebd.png

传入的 URL 中包含了 Provider 的地址(172.18.112.15:20880)、暴露的接口(org.apache.dubbo.demo.DemoService)等信息, toUrlPath() 方法会根据传入的 URL 参数确定在 ZooKeeper 上创建的节点路径,还会通过 URL 中的 dynamic 参数值确定创建的 ZNode 是临时节点还是持久节点。

URL 在服务订阅中的应用

Consumer 启动后会向注册中心进行订阅操作,并监听自己关注的 Provider。那 Consumer 是如何告诉注册中心自己关注哪些 Provider 呢?

我们来看 ZookeeperRegistry 这个实现类,它是由上面的 ZookeeperRegistryFactory 工厂类创建的 Registry 接口实现,其中的 doSubscribe() 方法是订阅操作的核心实现,在第 175 行打一个断点,并 Debug 启动 Demo 中 Consumer,会得到下图所示的内容:

06a6be3b78f2b0aa76e99c9afbab3cee.png

可以看到传入的 URL 参数如下:

consumer://...?application=dubbo-demo-api-consumer&category=providers,configurators,routers&interface=org.apache.dubbo.demo.DemoService...

其中 Protocol 为 consumer ,表示是 Consumer 的订阅协议,其中的 category 参数表示要订阅的分类,这里要订阅 providers、configurators 以及 routers 三个分类;interface 参数表示订阅哪个服务接口,这里要订阅的是暴露 org.apache.dubbo.demo.DemoService 实现的 Provider。

通过 URL 中的上述参数,ZookeeperRegistry 会在 toCategoriesPath() 方法中将其整理成一个 ZooKeeper 路径,然后调用 zkClient 在其上添加监听。

本文转自公众号:勾勾的Java宇宙

欢迎大家来留言互动哦!

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

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

相关文章

swarm 容器_Oracle应用容器云上的WildFly Swarm

swarm 容器在此博客文章中&#xff0c;我将描述如何将打包在WildFly Swarmber -jar中的CloudEE Duke应用程序部署到Oracle Application Container Cloud 。 在Oracle Application Container Cloud中进行部署所需的部署工件是一个ZIP归档文件&#xff0c;其中包含应用程序ber-j…

mysql数据库文件还原数据库_MySql通过数据库文件恢复数据库

以表”Table”为例:如类型是MyISAM, 数据文件则以”Table.frm””Table.MYD””Table.MYI””三个文件存储于”/data/$databasename/”目录中.如类型是InnoDB, 数据文件则存储在”$innodb_data_home_dir/″中的ibdata1文件中(一般情况)&#xff0c;结构文件存在于table_name.fr…

yum 如何知道从哪里下载包?

包来自什么地方呢&#xff1f;yum 如何知道从哪里下载包&#xff1f;起点是 /etc/yum.repos.d/ 目录&#xff0c;这个目录常常包含几个 repo 文件。这是 repo 的默认位置&#xff0c;但是可以在 YUM 配置文件&#xff08;通常是 /etc/yum.conf&#xff09;中指定其他位置。清单…

mysql主从修改系统参数步骤_mysql主从配置的参数配置与步骤_MySQL

mysql主从配置的参数配置与步骤_MySQL主从配置的步骤&#xff1a;在主库建立要同步的数据库,建立主库的帐号和修改主备库配置create database web default character set utf8grant replication slave on *.* to repdcssub192.168.191.112 identified by 123456;grant all priv…

javascript 解密_Javascript中的AES加密和Java中的解密

javascript 解密AES代表高级加密系统&#xff0c;它是一种对称加密算法&#xff0c;很多时候我们需要在客户端加密一些纯文本&#xff0c;例如密码&#xff0c;然后将其发送到服务器&#xff0c;然后由服务器解密以进行进一步处理.AES加密和解密更加容易在相同的平台&#xff0…

英文标点符号大全

标点符号英文中文名称未知反撇号’apostrophe撇号&#xff0c;缩写及所有格符号plus加号&#xff1b;正号-minus减号&#xff1b;负号plus or minus正负号is multiplied by乘号is divided by除号&#xff1d;is equal to等于号≠is not equal to不等于号≡is equivalent to全等…

Linux 系统下显示文件内容(查看文件内容)的命令 more/less/cat/head/tail 比较

命令说明more建议用于查看内容较长的文本文件&#xff0c;内容可以分屏显示&#xff0c;并且支持在显示时定位关键字cat建议用于查看内容较少的文本文件。当文件较大时&#xff0c;文本在屏幕上迅速闪过&#xff08;滚屏&#xff09;&#xff0c;用户往往看不清所显示的内容。因…

mysql子分区多少层_MySQL 子分区-阿里云开发者社区

介绍子分区其实是对每个分区表的每个分区进行再次分隔&#xff0c;目前只有RANGE和LIST分区的表可以再进行子分区&#xff0c;子分区只能是HASH或者KEY分区。子分区可以将原本的数据进行再次的分区划分。一、创建子分区子分区由两种创建方法&#xff0c;一种是不定义每个子分区…

gradle 编译java_Java的Gradle依赖关系,使用编译还是实现?

gradle 编译java当我向一位同事解释如何将Gradle用于Java项目时&#xff08;他正在远离Maven &#xff09;&#xff0c;我们遇到了各种代码示例。 一些示例将编译配置用于依赖项&#xff0c;而其他示例则使用Implements和api 。 dependencies { compile commons-httpclient:co…

Linux 命令之 typeset -- 声明 shell 变量,设置变量的属性

文章目录一、命令介绍二、常用选项三、命令示例&#xff08;1&#xff09;定义关联数组并访问一、命令介绍 typeset 命令是 bash 的内建命令&#xff0c;是命令 declare 的别名&#xff0c;两者是完全一样的&#xff0c;用来声明 shell 变量&#xff0c;设置变量的属性。 用于…

git log 迁移_现场故事:从Log4J迁移到Log4J2

git log 迁移通过从您的应用程序学习企业APM产品&#xff0c;发现更快&#xff0c;更有效的性能监控。 参加AppDynamics APM导览&#xff01; 与许多Java应用程序一样&#xff0c;AppDynamics Java代理广泛使用日志记录。 多年来&#xff0c;我们一直使用Log4J作为我们的日志记…

mysql firebird 性能_Firebird, MySQL 与 PostgreSQL 代码质量对比

今天看到一篇文章 - “Firebird, MySQL 与 PostgreSQL 代码质量对比”- 关于三个开源 RDBMS 的静态分析比较。主要内容A few words about the projectsFirebirdMySQLPostgreSQLPVS-StudioComparison criteriaWhy "head-on" comparison is not a good ideaAn alterna…

Linux 命令之 let -- bash 中用于计算的工具,用于执行一个或多个表达式

文章目录一、命令介绍二、命令示例自增操作自减操作shell 脚本中的运算表达式一、命令介绍 let 命令是 BASH 中用于计算的工具&#xff0c;用于执行一个或多个表达式&#xff0c;变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符&#xff0c;则必须引…

sun jdk 与jdk_Sun过去的世界中的JDK 11和代理

sun jdk 与jdk使用JDK 11后&#xff0c;就sun.misc.Unsafe的第一种方法。 其中&#xff0c; defineClass方法已删除。 代码生成框架通常使用此方法在现有的类加载器中定义新的类。 尽管此方法易于使用&#xff0c;但它的存在也使JVM本质上不安全&#xff0c;正如其定义类的名称…

php mysql上传多张图片_PHP开发之多个文件上传到MySql数据库(一)

前面的章节我们介绍了用PHP实现上传一个文件的教程。朋友们就会有疑问&#xff0c;怎么样才能上传多张多个文件到数据库&#xff1f;重点在于放入几个文件以后点击提交上传之后所有的文件一起上传&#xff0c;并且每个文件都给一个新的路径。提供一种思路&#xff1a;先获取每个…

jdk只有一个java进程_JDK 10:从Java访问Java应用程序的进程ID

jdk只有一个java进程StackOverflow.com上一个普遍的问题是&#xff1a;“ Java程序如何获得自己的进程ID&#xff1f; 与该问题相关的几个答案包括解析ManagementFactory返回的String 。 getRuntimeMXBean&#xff08;&#xff09; 。 getName&#xff08;&#xff09; [但是可…

Shell 脚本生成不重复的随机数

#!/bin/bash #AUTHOR:AN #DATE:2019-3-24 #Describe:Generate No-Repeat Random-Number #Method:如生成3~7的随机数&#xff0c;先生成0~4&#xff08;7-3&#xff09;的随机数&#xff0c;再加上3&#xff08;起始值&#xff09;来修正 #####################################…

python if语句能否判断中文_Python“if”语句被忽略

如果满足多个条件(“or”)中的一个&#xff0c;我将触发Python中的循环。脚本似乎跳过了“if”语句并在不满足所需条件的情况下进入内部循环。在编码# Begin TestCase# Main logic: execute RemoteController macro, if expected state true, set Success, else: Failfor macr…

payara 创建 集群_Payara Micro在Oracle应用容器云上

payara 创建 集群在此博客文章中&#xff0c;我将描述如何将打包在Payara Microber -jar中的CloudEE Duke应用程序部署到Oracle Application Container Cloud 。 在Oracle Application Container Cloud中进行部署所需的部署工件是一个ZIP归档文件&#xff0c;其中包含应用程序…