写点什么

Dubbo 中的统一契约是如何实现的?

  • 2022 年 5 月 07 日
  • 本文字数:1887 字

    阅读完需:约 6 分钟

在 dubbo-common 模块中,有一个 URL 类专门用于封装 URL,如下所示。



在 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, password without username!");


}


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);


// trim the beginning "/"


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 对于 URL 的核心封装,基本与互联网中的 URL 封装是一致的。


在 Dubbo 的 dubbo-common 模块提供了处理 URL 的工具类:URLBuilder 和 URLStrParser。如下所示。



这两个类的实现还是比较简单的,小伙伴们可以自行阅读 Dubbo 的源码。


接下来,我们一起来看看在 Dubbo 内部,URL 是如何实现统一契约的?


[](()Dubbo 中 URL 的实际应用




这里,我们主要通过三方面来简单聊聊 URL 在 Dubbo 内部的实际应用:


  • URL 在 SPI 中的应用。

  • URL 在服务注册中的应用。

  • URL 在服务发现中的应用。

[](()URL 在 SPI 中的应用

稍微了解过 Dubbo 的小伙伴都知道,Dubbo 具有高度的可扩展性,而这种扩展性是基于 Dubbo 自身的 SPI 来实现的。在 Dubbo 实现的 SPI 中,URL 又起到了非常重要的作用。


在 Dubbo SPI 的实现中,一个典型的场景就是被 @Adaptive 注解修饰的接口方法,例如,在 dubbo-registry-api 模块中的 RegistryFactory 接口中的 getRegistry()方法上被 @Adaptive({“protocol”})注解修饰。如下所示。



说明 RegistryFactory 接口中的 getRegistry()方法是一个适配器方法,Dubbo 在运行的过程中,会为 getRegistry()方法动态生成RegistryFactory$Adaptive类型。例如,生成的RegistryFactory$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;


String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());


if (extName == null)


throw new IllegalStateException("");


RegistryFactory extension = (RegistryFactory) ExtensionLoader.getExtensionLoader(RegistryFactory.class).getExtension(extName);


return extension.getRegistry(arg0);


}


}


这段代码相对来说还是比较容易理解的,生成的 RegistryFactory$Adaptive 会自动实现 getRegistry()方法,在 getRegistry()方法中,会获取 URL 中的 protocol 参数来确定 URL 的协议,如果获取的 protocol 为空,则使用默认的 dubbo 协议,有了这个协议,就能够通过 SPI 动态加载具体的扩展实现类。


我们在 Dubbo 的 dubbo-registry-api 模块中找到 RegistryProtocol 类,如下所示。



找到其中的 getRegistry()方法并打上断点,如下所示。



接下来,debug 启动 Dubbo 的 Provider 示例,如下所示。



可以看到,此时使用的 protocol 协议为 zookeeper。有关 Dubbo 中 SPI 的实现,我们后面再详细剖析,今天,小伙伴们有个大致的了解即可。

[](() 《一线大厂 Java 面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 URL 在服务注册中的应用

在 Dubbo 中的服务注册实现中,URL 同样起到了非常重要的作用。这里,我使用的注册中心是 Zookeeper,所以,我们在 dubbo-registry-zookeeper 模块中找到 ZookeeperRegistry 类,如下所示。



找到其中的 doRegister()方法,打上断点,如下所示。



debug 启动 Dubbo 自带的 provider 示例,如下所示。



可以看到,在注册到 Zookeeper 中的 URL 中,包含了 protocol 协议、host 主机名、port 端口号、path 请求路径,parameters 参数等信息。

[](()URL 在服务发现中的应用

Dubbo 中服务的消费者 Consumer 在启动时,会向 Zookeeper 注册中心订阅自身需要调用的服务,那具体是如何通过 URL 订阅的呢?我们同样在 dubbo-registry-zookeeper 模块中的 ZookeeperRegistry 类中找到 doSubscribe()方法。在 doSubscribe()方法中打上断点,如下所示。

用户头像

还未添加个人签名 2022.04.13 加入

还未添加个人简介

评论

发布
暂无评论
Dubbo中的统一契约是如何实现的?_Java_爱好编程进阶_InfoQ写作社区