Dubbo 中的 URL

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

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 对象

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() 方法中打一个断点, 得到如下图所示的内容:

这里传入的 registryUrl 值为:

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

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

URL 在服务暴露中的应用

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

传入的 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,会得到下图所示的内容:

可以看到传入的 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宇宙

欢迎大家来留言互动哦!

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

  1. dubbo protocol port 消费者端_Dubbo 优雅停机演进之路

    一.前言 在 『ShutdownHook- Java 优雅停机解决方案』 一文中我们聊到了 Java 实现优雅停机原理.接下来我们就跟根据上面知识点,深入 Dubbo 内部,去了解一下 Dubbo 如 ...

  2. dubbo protocol port 消费者端_企业级 SpringBoot 与 Dubbo 的并用

    点击上方"匠心零度",选择"设为星标" 做积极的人,而不是积极废人 作者:SimpleWu cnblogs.com/SimpleWu/p/10833555.ht ...

  3. dubbo protocol port 消费者端_springboot整合dubbo设置全局唯一ID进行日志追踪

    击上方蓝色"程序员白楠楠",选择"设为星标" 作者:松下听泉 出处:https://blog.csdn.net/weixin_39427718 1.新建项目 利 ...

  4. 客户连接多个服务端_Dubbo源码解析之客户端Consumer

    前面我们学习了Dubbo源码解析之服务端Provider.对服务提供方进行思路上的讲解,我们知道以下知识点.本篇文章主要对消费方进行讲解.废话不多说请看下文. 如何将对象方法生成Invoker 如何将 ...

  5. Dubbo第三讲:Dubbo的可扩展机制SPI源码解析

    本文是Dubbo第三讲:Dubbo的可扩展机制SPI源码解析 文章目录 1.Dubbo SPI机制 1.1.Dubbo具有良好拓展性的原因 1.2.Dubbo SPI和Java SPI的区别? 1.3 ...

  6. PHP服务端、Unity客户端 双端基础源码做avalon阿瓦隆桌游面sha(类似狼人游戏)支持WebGL、小程序发布

    文章目录 PHP服务端发布(Windows下演示) Windows 安装PHP 启动服务器 Linux家族 Unity客户端发布 发布Windows客户端 发布WebGL端 演示 源码解析 联系作者 ...

  7. zabbix 3.2.2 server端(源码包)安装部署 (一)【转】

    环境准备: 操作系统 CentOS 6.8 2.6.32-642.11.1.el6.x86_64 zabbix server 172.16.10.150 zabbix agent 172.16.10. ...

  8. 区块链JAVA数字交易所官方商业版开发级全套三端纯源码

    介绍: 区块链JAVA数字交易所官方商业版开发级全套三端纯源码 网盘下载地址: http://kekewangLuo.net/fsQqJmSy7st0 图片:

  9. 至尊版影视双端app源码对接苹果CMS 带商城码支付

    至尊版影视双端app源码对接苹果CMS 带商城体系投屏选集直播盒子码支出 安装说明: 前后端将域名替换为你的域名; 称号:通霸V5影视 改成你的影视称号; 后台登录账号密码去数据库ap_user查询! ...

最新文章

  1. 普华永道2030汽车产业报告 私家车真正Out了!
  2. MTU(最大传输单元)
  3. 【深度学习笔记】Precision、Recall
  4. C# Message 消息处理
  5. 私.Modbus测试_ZC02_串口方式
  6. 《算法学习与应用 从入门到精通》——填写运算符
  7. 同事操作两个数据源保持事务一致_「微服务架构」微服务架构中的数据一致性...
  8. P4562-[JXOI2018]游戏【数论,组合数学】
  9. vue 里面引入高德地图
  10. 光伏农业七大问题不解决 投资者恐“先驱”变“先烈”
  11. python terminal_在PyCharm的 Terminal(终端)切换Python版本的方法
  12. Spring-beans-BeanWrapper
  13. Firefly是什么?有什么特点?
  14. 类成员函数可以返回该类的实例吗_关于类的理解
  15. atitit.导航的实现最佳实践and声明式编程
  16. 【MCVRP】基于matlab模拟退火算法求解带多种容量的车辆路径规划问题【含Matlab源码 918期】
  17. 客快物流大数据项目(二十九):下载CDH的安装包
  18. 财富智慧 幸福人生——《菁英财商训练营》首场活动在深圳龙岗文博宫举行
  19. Ubuntu根目录的各个文件夹的介绍
  20. 眼保健操练习方法,眼保健操图解教程

热门文章

  1. cloud foundry_使用“另类” Cloud Foundry Gradle插件无需停机
  2. lucene使用3.0.3_Apache Lucene 5.0.0即将发布!
  3. 输入流输出流是以内存为标准_构建用于测试的超大内存输入流
  4. Java的@Serial批注
  5. jgroups传输消息_使用JGroups进行ElasticMQ消息复制
  6. 如何:在Spring中使用@Conditional和Condition注册组件
  7. Java TDD简介–第1部分
  8. 注释,无处不在的注释
  9. Java:逐步读取/流式传输CSV文件
  10. 再见了古诺。 你好Drools工作台。