Dubbo配置总线(URL)解析

1,269 阅读3分钟

URL 是整个 Dubbo 中非常基础,也是非常核心的一个组件,Dubbo很多方法都是以 URL 作为参数的,在方法内部解析传入的 URL 得到有用的参数,所以 URL 也称为Dubbo 的配置总线。

URL构成:

protocol://username:password@host:port/path?key=value&key=value

  • protocol: URL 的协议。常见的就是 HTTP 协议和 HTTPS 协议,当然,还有其他协议,如 FTP 协议等。
  • username/password: 用户名/密码。 HTTP Basic Authentication 中多会使用在 URL 的协议之后直接携带用户名和密码的方式。
  • host/port: 主机/端口。在实践中一般会使用域名,而不是使用具体的 host 和 port。
  • path: 请求的路径。
  • parameters: 参数键值对。一般在 GET 请求中会将参数放到 URL 中,POST 请求会将参数放到请求体中。

Dubbo 中的 URL:

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×tamp=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 的构造方法,可以看到其核心字段与前文分析的 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 对象。

在 Dubbo 中使用 URL 的好处多多,增加了便捷性:

  • 使用 URL 这种公共契约进行上下文信息传递,最重要的就是代码更加易读、易懂,不用花大量时间去揣测传递数据的格式和含义,进而形成一个统一的规范,使得代码易写、易读。
  • 使用 URL 作为方法的入参(相当于一个 Key/Value 都是 String 的 Map),它所表达的含义比单个参数更丰富,当代码需要扩展的时候,可以将新的参数以 Key/Value 的形式追加到 URL 之中,而不需要改变入参或是返回值的结构。
  • 使用 URL 这种“公共的契约”可以简化沟通,人与人之间的沟通消耗是非常大的,信息传递的效率非常低,使用统一的契约、术语、词汇范围,可以省去很多沟通成本,尽可能地提高沟通效率。

Dubbo 中的 URL 示例:

1.URL在SPI中应用

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

2. URL 在服务暴露中的应用

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

3. URL 在服务订阅中的应用

Consumer 启动后会向注册中心进行订阅操作,并监听自己关注的 Provider, 订阅ZooKeeper时,传入的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 在其上添加监听。