Dubbo 中的 URL 統一模型

Kirito的部落格發表於2019-01-04

定義

在不談及 dubbo 時,我們中的大多數人對 URL 這個概念並不會感到陌生。統一資源定位器 (RFC1738――Uniform Resource Locators (URL))應該是最廣為人知的一個 RFC 規範,它的定義也非常簡單

因特網上的可用資源可以用簡單字串來表示,該文件就是描述了這種字串的語法和語 義。而這些字串則被稱為:“統一資源定位器”(URL)

一個標準的 URL 格式至多可以包含如下的幾個部分

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

一些典型 URL

http://www.facebook.com/friends?param1=value1&param2=value2https://username:password@10.20.130.230:8080/list?version=1.0.0ftp://username:password@192.168.1.7:21/1/read.txt

當然,也有一些不太符合常規的 URL,也被歸類到了 URL 之中

  1. 192.168.1.3:20880

  2. url protocol = null, url host = 192.168.1.3, port = 20880, url path = null



  3. file:///home/user1/router.js?type=script

  4. url protocol = file, url host = null, url path = home/user1/router.js



  5. file://home/user1/router.js?type=script<br>

  6. url protocol = file, url host = home, url path = user1/router.js



  7. file:///D:/1/router.js?type=script

  8. url protocol = file, url host = null, url path = D:/1/router.js



  9. file:/D:/1/router.js?type=script

  10. 同上 file:///D:/1/router.js?type=script



  11. /home/user1/router.js?type=script

  12. url protocol = null, url host = null, url path = home/user1/router.js



  13. home/user1/router.js?type=script

  14. url protocol = null, url host = home, url path = user1/router.js

Dubbo 中的 URL

在 dubbo 中,也使用了類似的 URL,主要用於在各個擴充套件點之間傳遞資料,組成此 URL 物件的具體引數如下:

  • protocol:一般是 dubbo 中的各種協議 如:dubbo thrift http zk

  • username/password:使用者名稱/密碼

  • host/port:主機/埠

  • path:介面名稱

  • parameters:引數鍵值對

public URL(String protocol, String username, String password, String host, int port, String path, Map<String, String> parameters) {   if ((username == null || username.length() == 0)          && password != null && password.length() > 0) {      throw new IllegalArgumentException("Invalid url, password without username!");   }   this.protocol = protocol;   this.username = username;   this.password = password;   this.host = host;   this.port = (port < 0 ? 0 : port);   this.path = path;   // trim the beginning "/"   while(path != null && path.startsWith("/")) {       path = path.substring(1);   }   if (parameters == null) {       parameters = new HashMap<String, String>();   } else {       parameters = new HashMap<String, String>(parameters);   }   this.parameters = Collections.unmodifiableMap(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

  2. 描述一個 dubbo 協議的服務


  3. zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=demo-consumer&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=1214&qos.port=33333&timestamp=1545721981946

  4. 描述一個 zookeeper 註冊中心


  5. consumer://30.5.120.217/org.apache.dubbo.demo.DemoService?application=demo-consumer&category=consumers&check=false&dubbo=2.0.2&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=1209&qos.port=33333&side=consumer&timestamp=1545721827784

  6. 描述一個消費者

可以說,任意的一個領域中的一個實現都可以認為是一類 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:// 協議頭識別,直接呼叫 DubboProtocolexport() 方法,開啟服務埠。

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:// 協議頭識別,就會呼叫 RegistryProtocolexport() 方法,將 export 引數中的提供者 URL,先註冊到註冊中心。

再重新傳給 Protocol 擴充套件點進行暴露: dubbo://service-host/com.foo.FooService?version=1.0.0,然後基於擴充套件點自適應機制,透過提供者 URL 的 dubbo:// 協議頭識別,就會呼叫 DubboProtocolexport() 方法,開啟服務埠。

引用服務

1. 直連引用服務:

在沒有註冊中心,直連提供者的情況下, ReferenceConfig 解析出的 URL 的格式為: dubbo://service-host/com.foo.FooService?version=1.0.0

基於擴充套件點自適應機制,透過 URL 的 dubbo:// 協議頭識別,直接呼叫 DubboProtocolrefer() 方法,返回提供者引用。

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:// 協議頭識別,就會呼叫 RegistryProtocolrefer() 方法,基於 refer 引數中的條件,查詢提供者 URL,如: dubbo://service-host/com.foo.FooService?version=1.0.0

基於擴充套件點自適應機制,透過提供者 URL 的 dubbo:// 協議頭識別,就會呼叫 DubboProtocolrefer() 方法,得到提供者引用。

然後 RegistryProtocol 將多個提供者引用,透過 Cluster 擴充套件點,偽裝成單個提供者引用返回。

URL 統一模型的意義

對於 dubbo 中的 URL,有人理解為配置匯流排,有人理解為統一配置模型,說法雖然不同,但都是在表達一個意思,這樣的 URL 在 dubbo 中被當做是公共契約,所有擴充套件點引數都包含 URL 引數,URL 作為上下文資訊貫穿整個擴充套件點設計體系。

在沒有 URL 之前,只能以字串傳遞引數,不停的解析和拼裝,導致相同型別的介面,引數時而 Map, 時而 Parameters 類包裝:

export(String url) createExporter(String host, int port, Parameters params)

使用 URL 一致性模型:

export(URL url) createExporter(URL url)

在最新的 dubbo 程式碼中,我們可以看到大量使用 URL 來進行上下文之間資訊的傳遞,這樣的好處是顯而易見的:

1.   使得程式碼編寫者和閱讀者能夠將一系列的引數聯絡起來,進而形成規範,使得程式碼易寫,易讀。

2.   可擴充套件性強,URL 相當於引數的集合(相當於一個 Map),他所表達的含義比單個引數更豐富,當我們在擴充套件程式碼時,可以將新的引數追加到 URL 之中,而不需要改變入參,返參的結構。

3.   統一模型,它位於 org.apache.dubbo.common 包中,各個擴充套件模組都可以使用它作為引數的表達形式,簡化了概念,降低了程式碼的理解成本。

如果你能夠理解 final 契約和 restful 契約,那我相信你會很好地理解 URL 契約。契約的好處我還是囉嗦一句:大家都這麼做,就形成了默契,溝通是一件很麻煩的事,統一 URL 模型可以省去很多溝通成本,這邊是 URL 統一模型存在的意義。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31556476/viewspace-2305549/,如需轉載,請註明出處,否則將追究法律責任。

相關文章