Dubbo 中的 URL 统一模型
定义
在不谈及 dubbo 时,我们大多数人对 URL 这个概念并不会感到陌生。统一资源定位器 (RFC1738――Uniform Resource Locators (URL))应该是最广为人知的一个 RFC 规范,它的定义也非常简单
因特网上的可用资源可以用简单字符串来表示,该文档就是描述了这种字符串的语法和语
义。而这些字符串则被称为:“统一资源定位器”(URL)
** 一个标准的 URL 格式 ** 至多可以包含如下的几个部分
1 | protocol://username:password@host:port/path?key=value&key=value |
** 一些典型 URL**
1 | http://www.facebook.com/friends?param1=value1¶m2=value2 |
当然,也有一些 ** 不太符合常规的 URL**,也被归类到了 URL 之中
1 | 192.168.1.3:20880 |
Dubbo 中的 URL
在 dubbo 中,也使用了类似的 URL,主要用于在各个扩展点之间传递数据,组成此 URL 对象的具体参数如下:
- protocol:一般是 dubbo 中的各种协议 如:dubbo thrift http zk
- username/password:用户名 / 密码
- host/port:主机 / 端口
- path:接口名称
- parameters:参数键值对
1 | public URL(String protocol, String username, String password, String host, int port, String path, Map<String, String> parameters) { |
可以看出,dubbo 认为 protocol,username,passwored,host,port,path 是主要的 URL 参数,其他键值对村房子啊 parameters 之中。
** 一些典型的 Dubbo URL**
1 | dubbo://192.168.1.6:20880/moe.cnkirito.sample.HelloService?timeout=3000 |
可以说,任意的一个领域中的一个实现都可以认为是一类 URL,dubbo 使用 URL 来统一描述了元数据,配置信息,贯穿在整个框架之中。
URL 相关的生命周期
解析服务
基于 dubbo.jar 内的 META-INF/spring.handlers
配置,Spring 在遇到 dubbo 名称空间时,会回调 DubboNamespaceHandler
。
所有 dubbo 的标签,都统一用 DubboBeanDefinitionParser
进行解析,基于一对一属性映射,将 XML 标签解析为 Bean 对象。
在 ServiceConfig.export()
或 ReferenceConfig.get()
初始化时,将 Bean 对象转换 URL 格式,所有 Bean 属性转成 URL 的参数。
然后将 URL 传给协议扩展点,基于扩展点自适应机制,根据 URL 的协议头,进行不同协议的服务暴露或引用。
暴露服务
1. 只暴露服务端口:
在没有注册中心,直接暴露提供者的情况下,ServiceConfig
解析出的 URL 的格式为:dubbo://service-host/com.foo.FooService?version=1.0.0
。
基于扩展点自适应机制,通过 URL 的 dubbo://
协议头识别,直接调用 DubboProtocol
的 export()
方法,打开服务端口。
2. 向注册中心暴露服务:
在有注册中心,需要注册提供者地址的情况下,ServiceConfig
解析出的 URL 的格式为: registry://registry-host/org.apache.dubbo.registry.RegistryService?export=URL.encode("dubbo://service-host/com.foo.FooService?version=1.0.0")
,
基于扩展点自适应机制,通过 URL 的 registry://
协议头识别,就会调用 RegistryProtocol
的 export()
方法,将 export
参数中的提供者 URL,先注册到注册中心。
再重新传给 Protocol
扩展点进行暴露: dubbo://service-host/com.foo.FooService?version=1.0.0
,然后基于扩展点自适应机制,通过提供者 URL 的 dubbo://
协议头识别,就会调用 DubboProtocol
的 export()
方法,打开服务端口。
引用服务
1. 直连引用服务:
在没有注册中心,直连提供者的情况下,ReferenceConfig
解析出的 URL 的格式为:dubbo://service-host/com.foo.FooService?version=1.0.0
。
基于扩展点自适应机制,通过 URL 的 dubbo://
协议头识别,直接调用 DubboProtocol
的 refer()
方法,返回提供者引用。
2. 从注册中心发现引用服务:
在有注册中心,通过注册中心发现提供者地址的情况下,ReferenceConfig
解析出的 URL 的格式为:registry://registry-host/org.apache.dubbo.registry.RegistryService?refer=URL.encode("consumer://consumer-host/com.foo.FooService?version=1.0.0")
。
基于扩展点自适应机制,通过 URL 的 registry://
协议头识别,就会调用 RegistryProtocol
的 refer()
方法,基于 refer
参数中的条件,查询提供者 URL,如: dubbo://service-host/com.foo.FooService?version=1.0.0
。
基于扩展点自适应机制,通过提供者 URL 的 dubbo://
协议头识别,就会调用 DubboProtocol
的 refer()
方法,得到提供者引用。
然后 RegistryProtocol
将多个提供者引用,通过 Cluster
扩展点,伪装成单个提供者引用返回。
URL 统一模型的意义
对于 dubbo 中的 URL,有人理解为配置总线,有人理解为统一配置模型,说法虽然不同,但都是在表达一个意思,这样的 URL 在 dubbo 中被当做是 公共契约,所有扩展点参数都包含 URL 参数,URL 作为上下文信息贯穿整个扩展点设计体系。
在没有 URL 之前,只能以字符串传递参数,不停的解析和拼装,导致相同类型的接口,参数时而 Map, 时而 Parameters 类包装:
1 | export(String url) |
使用 URL 一致性模型:
1 | export(URL url) |
在最新的 dubbo 代码中,我们可以看到大量使用 URL 来进行上下文之间信息的传递,这样的好处是显而易见的:
- 使得代码编写者和阅读者能够将一系列的参数联系起来,进而形成规范,使得代码易写,易读。
- 可扩展性强,URL 相当于参数的集合 (相当于一个 Map),他所表达的含义比单个参数更丰富,当我们在扩展代码时,可以将新的参数追加到 URL 之中,而不需要改变入参,返参的结构。
- 统一模型,它位于 org.apache.dubbo.common 包中,各个扩展模块都可以使用它作为参数的表达形式,简化了概念,降低了代码的理解成本。
如果你能够理解 final 契约和 restful 契约,那我相信你会很好地理解 URL 契约。契约的好处我还是啰嗦一句:大家都这么做,就形成了默契,沟通是一件很麻烦的事,统一 URL 模型可以省去很多沟通成本,这边是 URL 统一模型存在的意义。
Dubbo 中的 URL 统一模型