dubbo服務暴露

前期準備

<dubbo:service/> 服務配置,用于暴露一個服務,定義服務的元信息,一個服務可以用多個協議暴露,一個服務也可以注冊到多個注冊中心。
eg、<dubbo:service ref="demoService" interface="com.xxx.xxx.provider.DemoService" />

<dubbo:reference/> 引用服務配置,用于創建一個遠程服務代理,一個引用可以指向多個注冊中心。
eg、<dubbo:reference id="demoService" interface="com.xxx.xxx.provider.DemoService" />

<dubbo:protocol/> 協議配置,用于配置提供服務的協議信息,協議由提供方指定,消費方被動接受。
eg、<dubbo:protocol name="dubbo" port="20880" />

<dubbo:application/> 應用配置,用于配置當前應用信息,不管該應用是提供者還是消費者。
eg、<dubbo:application name="provider" />

<dubbo:module/> 模塊配置,用于配置當前模塊信息,可選。
<dubbo:registry/> 注冊中心配置,用于配置連接注冊中心相關信息。
eg、<dubbo:registry address="zookeeper://192.168.2.249:2181" />

<dubbo:monitor/> 監控中心配置,用于配置連接監控中心相關信息,可選。
<dubbo:provider/> 提供方的缺省值,當ProtocolConfig和ServiceConfig某屬性沒有配置時,采用此缺省值,可選。
<dubbo:consumer/> 消費方缺省配置,當ReferenceConfig某屬性沒有配置時,采用此缺省值,可選。
<dubbo:method/> 方法配置,用于ServiceConfig和ReferenceConfig指定方法級的配置信息。
<dubbo:argument/> 用于指定方法參數配置。

Invoker URL ServiceBean

URL 之于 Dubbo,猶如水之于魚,非常重要。

在 Dubbo 中,Invoker 是一個非常重要的模型。在服務提供端,以及服務引用端均會出現 Invoker。Dubbo 官方文檔中對 Invoker 進行了說明,這里引用一下。

Invoker 是實體域,它是 Dubbo 的核心模型,其它模型都向它靠擾,或轉換成它,它代表一個可執行體,可向它發起 invoke 調用,它有可能是一個本地的實現,也可能是一個遠程的實現,也可能一個集群實現。

1.概覽

image

http://dubbo.apache.org/zh-cn/docs/dev/implementation.html

<dubbo:service/> → ServiceConfig→Invoker→ Exporter->啟動server打開端口->注冊

1.dubbo在什么時候進行服務暴露

[圖片上傳失敗...(image-aaadb7-1562576327193)]

[圖片上傳失敗...(image-ff9460-1562576327192)]

導出時機:
afterPropertiesSet

onApplicationEvent

為什么要延遲暴露

dubbo服務導出到那里?

導出了什么東西

怎么導出的

2.服務暴露過程
  • 1.檢查準備環境配置
  • 2.加載注冊中心
  • 3.暴露本地服務
  • 4.暴露遠程服務
  • 5.注冊

導出的入口
org.apache.dubbo.config.ServiceConfig#export

  1. 檢測 <dubbo:service> 標簽的 interface 屬性合法性,不合法則拋出異常
  2. 檢測 ProviderConfig、ApplicationConfig 等核心配置類對象是否為空,若為空,則嘗試從其他配置類對象中獲取相應的實例。
  3. 檢測并處理泛化服務和普通服務類(擴展泛化調用)
  4. 檢測本地存根配置,并進行相應的處理(解釋存根)
    image
  5. 對 ApplicationConfig、RegistryConfig 等配置類進行檢測,為空則嘗試創建,若無法創建則拋出異常

檢查配置舉個例子 protocol

如果為空就set,然后增加屬性

[圖片上傳失敗...(image-819df9-1562576327192)]

  • 2.加載注冊中心

[圖片上傳失敗...(image-10b9e0-1562576327192)]

[圖片上傳失敗...(image-3c064c-1562576327192)]

org.apache.dubbo.config.AbstractInterfaceConfig#loadRegistries的registries什么時候注入的?提出問題
org.springframework.beans.factory.BeanFactoryUtils#beansOfTypeIncludingAncestors(org.springframework.beans.factory.ListableBeanFactory, java.lang.Class<T>, boolean, boolean)
這里獲取默認的配置 擴展IOC

雙注冊中心
haunt 資料
https://tech.youzan.com/haunt-youzan-service-discovery/

org.apache.dubbo.config.ServiceConfig#doExportUrlsFor1Protocol

1.將一些信息,比如版本、時間戳、方法名以及各種配置對象的字段信息放入到 map 中,map 中的內容將作為 URL 的查詢字符串。構建好 map 后,緊接著是獲取上下文路徑、主機名以及端口號等信息。最后將 map 和主機名等數據傳給 URL 構造方法創建 URL 對象。

[圖片上傳失敗...(image-70bad3-1562576327192)]

3.暴露本地服務org.apache.dubbo.config.ServiceConfig#exportLocal

先看一下成員變量。使用spi

[圖片上傳失敗...(image-53fddf-1562576327192)]

[圖片上傳失敗...(image-d81aee-1562576327192)]

創建invoker的過程

[圖片上傳失敗...(image-47e326-1562576327192)]

生成的protocol code

package org.apache.dubbo.rpc;
import org.apache.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol {
    public void destroy() {
        throw new UnsupportedOperationException("The method public abstract void org.apache.dubbo.rpc.Protocol.destroy() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }
    public int getDefaultPort() {
        throw new UnsupportedOperationException("The method public abstract int org.apache.dubbo.rpc.Protocol.getDefaultPort() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }
    public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, org.apache.dubbo.common.URL arg1) throws org.apache.dubbo.rpc.RpcException {
        if (arg1 == null) throw new IllegalArgumentException("url == null");
        org.apache.dubbo.common.URL url = arg1;
        String extName = (url.getProtocol() == null ? "dubbo": url.getProtocol());
        if (extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
        org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.refer(arg0, arg1);
    }
    public org.apache.dubbo.rpc.Exporter export(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException {
        if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
        if (arg0.getUrl() == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
        org.apache.dubbo.common.URL url = arg0.getUrl();
        String extName = (url.getProtocol() == null ? "dubbo": url.getProtocol());
        if (extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
        org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.export(arg0);
    }
}

String extName = (url.getProtocol() == null ? "dubbo": url.getProtocol());
org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);

最后得到
org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol

[圖片上傳失敗...(image-d3033f-1562576327192)]

回憶getExtension的時候,對Protocol包裝又包裝。

build一個過濾鏈,啟動一個服務質量監控服務器,增加一個監聽者。

[圖片上傳失敗...(image-93aad6-1562576327192)]

為什么要有本地暴露

本地調用使用了 injvm 協議,是一個偽協議,它不開啟端口,不發起遠程調用,只在 JVM 內直接關聯,但執行 Dubbo 的 Filter 鏈。

http://dubbo.apache.org/zh-cn/docs/user/demos/local-call.html

org.apache.dubbo.registry.integration.RegistryProtocol#doLocalExport

org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#openServer

[圖片上傳失敗...(image-ffbf2d-1562576327192)]

[圖片上傳失敗...(image-1fea4f-1562576327192)]

org.apache.dubbo.rpc.Protocol#export 遠程暴露

org.apache.dubbo.registry.integration.RegistryProtocol#export

遠程暴露第一步 交給具體的協議去暴露本地端口

org.apache.dubbo.registry.integration.RegistryProtocol#doLocalExport

→org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#export(緩存exporter)

→org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#openServer(緩存server)

→org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#createServer(給url增加一些屬性)

  ->org.apache.dubbo.remoting.exchange.Exchangers#bind(org.apache.dubbo.common.URL, org.apache.dubbo.remoting.exchange.ExchangeHandler)(根據type獲取對應的exchanger)

     ->org.apache.dubbo.remoting.Transporters#bind(org.apache.dubbo.common.URL, org.apache.dubbo.remoting.ChannelHandler...)(門面模式,具體交給netty去做)

        ->org.apache.dubbo.remoting.transport.netty4.NettyServer#doOpen(真正啟動server的地方)

[圖片上傳失敗...(image-498383-1562576327192)]

第二步-注冊

獲取注冊中心

org.apache.dubbo.registry.support.AbstractRegistryFactory#getRegistry

→org.apache.dubbo.registry.etcd.EtcdRegistryFactory#createRegistry

→org.apache.dubbo.remoting.etcd.jetcd.JEtcdTransporter#connect

[圖片上傳失敗...(image-c652f9-1562576327192)]

org.apache.dubbo.remoting.etcd.support.AbstractEtcdClient#create

[圖片上傳失敗...(image-3893ab-1562576327192)]

org.apache.dubbo.remoting.etcd.jetcd.JEtcdClientWrapper#createPersistent

[圖片上傳失敗...(image-71c6f8-1562576327192)]

模板方法

重點是把dubbo的url轉換成etcd的節點

為啥注冊中心掛了,服務還能繼續通信?

com.alibaba.dubbo.registry.RegistryService#subscribe

最后。官網的說明

URL舉例

dubbo://172.17.48.52:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.0.2&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello

服務提供者暴露一個服務的詳細過程

image

上圖是服務提供者暴露服務的主過程:

首先 ServiceConfig 類拿到對外提供服務的實際類 ref(如:HelloWorldImpl),然后通過 ProxyFactory 類的 getInvoker 方法使用 ref 生成一個 AbstractProxyInvoker 實例,到這一步就完成具體服務到 Invoker的轉化。接下來就是 Invoker 轉換到 Exporter 的過程。

Dubbo 處理服務暴露的關鍵就在 Invoker 轉換到 Exporter 的過程,上圖中的紅色部分。下面我們以 Dubbo 和 RMI 這兩種典型協議的實現來進行說明:

Dubbo 的實現

Dubbo 協議的 Invoker 轉為 Exporter 發生在 DubboProtocol 類的 export 方法,它主要是打開 socket 偵聽服務,并接收客戶端發來的各種請求,通訊細節由 Dubbo 自己實現。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 在Spring將xml中的各個標簽解析成一個個BeanDefinition之后,接下來就是根據BeanDefini...
    spilledyear閱讀 982評論 0 5
  • 筆記簡述何所謂服務暴露,其實就是服務提供方把自己的服務提供出來,使得其他服務使用方能夠跨網絡(本地就不需要跨網絡)...
    jwfy閱讀 1,291評論 0 2
  • 筆記簡述Dubbo服務暴露之前分為了兩小節Dubbo 服務暴露 源碼學習(上)(三) 和Dubbo 服務暴露 源碼...
    jwfy閱讀 900評論 1 3
  • 作為分布式框架,最核心的功能無非是服務的暴露和服務的引用,今天我們先說服務的暴露。 我們先從暴露服務配置說起 我們...
    數齊閱讀 10,431評論 2 12
  • 先看官網兩張圖【引用來自官網】:image.png 官網說明: 1.首先 ReferenceConfig 類的 i...
    致慮閱讀 1,045評論 0 2