xml界面如何从url地址中获取参数值 源码_Dubbo源码:搞定URL,就走完了进度条的一半...

Dubbo 中的 URL

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

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

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

3c50f52d66abb712d7b6ca9c172256a1.png

这里传入的 registryUrl 值为:

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

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

URL 在服务暴露中的应用

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

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

111360941c91e7e44df0a83e1392fdab.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 在其上添加监听。

推荐阅读:

Dubbo源码:跟着Demo学习基本使用

令人心动的Coder:算法女神带你变身大厂offer收割机急!面试中被问到“元空间”怎么破?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值