9 - 遠程服務暴露

騰一部分筆記到csdn

 

1. 概述

如果不熟悉該協議,可以先看看 《Dubbo 使用指南 —— dubbo://》 ,簡單瞭解即可。
相比本地暴露遠程暴露會多做如下幾件事情:
  • 啓動通信服務器,綁定服務端口,提供遠程調用。
  • 向註冊中心註冊服務提供者,提供服務消費者從註冊中心發現服務。
 

2. 遠程暴露源碼分析

在 #doExportUrlsFor1Protocol(protocolConfig, registryURLs) 方法中,涉及遠程暴露服務的流程如下
ServiceConfig.java
->doExportUrlsFor1Protocol()
//registryURLs
->循環registryURLs
->URL monitorUrl = loadMonitor(registryURL);//添加監控
->Invoker<?> invoker= proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));//創建Invoker,本地暴露有介紹
->DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this); //封裝一下
 
->Exporter<?> exporter= protocol.export(wrapperInvoker); //暴露服務
    Protocol$Adpative.java
    -> extension =  ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension("registry"); //獲取到的是註冊中心協議
    -> extension.export(arg0)
    -> ProtocolFilterWrapper.export // 和本地暴露一樣,這裏不細講
    -> ProtocolListenerWrapper.export// 和本地暴露一樣,這裏不細講
   
    RegistryProtocol.java
    -> export()
        -> final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker); // 啓動本地通訊服務
 
            -> ExporterChangeableWrapper<T> exporter = (ExporterChangeableWrapper<T>) bounds.get(key); //查看是否已經向註冊中心註冊
           
            -> exporter等於null就創建,exporter = new ExporterChangeableWrapper<T>((Exporter<T>) protocol.export(invokerDelegete),originInvoker);
            -> Protocol$Adpative.export()
            -> extension = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension("dubbo");
            -> extension.export(arg0)
            -> ProtocolFilterWrapper.export // 和本地暴露一樣,這裏不細講
            -> ProtocolListenerWrapper.export// 和本地暴露一樣,這裏不細講
1.netty服務暴露的開始-------
            DubboProtocol.java
            -> export()
              -> DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap); //創建dubboExporter
              -> exporterMap.put(key, exporter); // key等於${group}/${interface}:${version}:${port}
 
              -> openServer(url); // 啓動服務
                  -> createServer(url) //創建Service
                      -> server = Exchangers.bind(url, requestHandler);//exchaanger是一個信息交換層,注意這裏面的requestHandler,就是處理網絡請求的,是DubboProtocol實現。通過服務keyprotocolexpoerts裏面找expoert,裏面有invoker
2.信息交換層exchanger開始   -> ExtensionLoader.getExtensionLoader(Exchanger.class).getExtension("header")
                          HeaderExchanger.java
                          -> bind()
                              -> return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
3.網絡傳輸層 transporter--------->Transporters.bind()
                              -> ExtensionLoader.getExtensionLoader(Transporter.class).getAdaptiveExtension()
                              Transporter$Adpative.java
                              -> extension = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.remoting.Transporter.class).getExtension("netty");
                              -> extension.bind(arg0, arg1)
                              NettyTransporter.java
                              -> bind()
                                  -> new NettyServer(url, listener) //下面都是對應構造方法
                                      AbstractPeer //this.url = url;    this.handler = handler;
                                      AbstractEndpoint//codec  timeout=1000  connectTimeout=3000
                                      AbstractServer //bindAddress accepts=0 idleTimeout=600000
4.打開斷開,暴露netty服務-------------> doOpen()
                                        -> 設置NioServerSocketChannelFactory boss worker的線程池 線程個數爲3
                                        -> 設置編解碼 hander
                                        -> bootstrap.bind(getBindAddress())
                              -> this.server=NettyServer
                              -> heartbeat=60000
                              -> heartbeatTimeout=180000
                              -> startHeatbeatTimer()//這是一個心跳定時器,採用了線程池,如果斷開就心跳重連。
 
        -> URL registryUrl = getRegistryUrl(originInvoker); //獲取註冊中心URL
        -> final Registry registry = getRegistry(originInvoker); // 獲取註冊中心對象
        -> final URL registedProviderUrl = getRegistedProviderUrl(originInvoker); //獲取服務提供者URL
        -> register(registryUrl, registedProviderUrl); // 向註冊中心註冊
 
        -> final URL overrideSubscribeUrl = getSubscribedOverrideUrl(registedProviderUrl); //創建監聽配置規則URL
        -> final OverrideListener overrideSubscribeListener = newOverrideListener(overrideSubscribeUrl, originInvoker); //創建監聽器
        -> registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener); //註冊監聽器
 
<-------—> returnnew DestroyableExporter<T>(exporter, originInvoker, overrideSubscribeUrl, registedProviderUrl); //返回一個Exporter
->exporters.add(exporter); //添加到exporters
 
// 暴露服務但不向註冊中心暴露
->Invoker<?> invoker= proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
->DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
->Exporter<?> exporter= protocol.export(wrapperInvoker);
->exporters.add(exporter);
 
 
 
 
 
->Exporter<?> exporter= protocol.export(wrapperInvoker); //暴露服務
    此處 Dubbo SPI 自適應的特性的好處就出來了,可以自動根據 URL 參數,獲得對應的拓展實現。例如,invoker 傳入後,根據 invoker.url 自動獲得對應 Protocol 拓展實現爲 ReigsterProtocol 。RegistryProtocol 會在其 #export(...) 方法中,使用服務提供者的 URL ( 即註冊中心的 URL 的 export 參數值),再次調用 Protocol$Adaptive 獲取到的是 DubboProtocol 對象,進行服務暴露。
 
RegistryProtocol#export(...) {
    // 1. 啓動本地服務器
    DubboProtocol#export(...);
    // 2. 向註冊中心註冊。 
}
實際上,Protocol 有兩個 Wrapper 拓展實現類: ProtocolFilterWrapper、ProtocolListenerWrapper 。所以,#export(...) 方法的調用順序是:
      • Protocol$Adaptive => ProtocolFilterWrapper => ProtocolListenerWrapper => RegistryProtocol
      •  => 
      • Protocol$Adaptive => ProtocolFilterWrapper => ProtocolListenerWrapper => DubboProtocol
      • 由於ProtocolFilterWrapper、ProtocolListenerWrapper均有判斷如果是RegistryProtocol就不處理
 
 
 
 
 
-> URL registryUrl = getRegistryUrl(originInvoker); //獲取註冊中心URL
 
originInvoker裏面的URL等於。  registry://註冊中心ip: 端口/com.alibaba.dubbo.registry.RegistryService?register=zookee & export=服務URL,這裏解析成
 
zookeeper://100.66.178.66:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.0 &export=dubbo%3A%2F%2F100.66.151.177%3A20881%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo- provider%26bind.ip%3D100.66.151.177%26bind.port%3D20881%26default.delay%3D-1%26default.retries%3D0%26delay%3D1%26dubbo%3D2.0.0%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26logger%3Djcl%26methods%3DcallbackParam%2CsayHello%2Csave//%2Cupdate%2Csay03%2Cdelete%2Csay04%2Cdemo%2Csay01%2Csay02%2Cbye%2Chello02%2Csaves%2Chello01%2Chello%26pid%3D865%26qos.port%3D22222%26side%3Dpro//vider%26timestamp%3D1576056813900&logger=jcl&pid=865&qos.port=22222&timestamp=1576056813884
 

該過程是我們在 3* - API 配置(二)之服務提供者的那張圖的反向流程,即紅線部分 :

 

 

 
-> server = Exchangers.bind(url, requestHandler);//exchaanger是一個信息交換層,注意這裏面的requestHandler,就是處理網絡請求的,是DubboProtocol實現。通過服務keyprotocolexpoerts裏面找expoert,裏面有invoker
    開啓服務器,這裏簡述下 具體細節如果後面理解了再長篇解釋。   
    requestHanlder是DubboProticol裏面new出來裏的,他有一個處理方法處理遠程調用傳過了的Invocation(所以通過遠程傳輸的僅僅是Invocation對象序列化後)解析 從exportMap取出對應的invoker,來調用方法對應方法獲取返回結果。
requestHanlder會被封在HeaderExchangeHandler->DecodeHandler了裏,通過Exchangers-》HeaderExchanger-》Transporters-〉最終給到NettyTransporter,傳遞到Nettyserver。
當nettyServer收到信息就會交給requestHanlder處理,獲取結果返回
這裏有兩個問題要解決Exchangers、Transporters作爲兩個門面模式對應Exchanger和Transporter,但到底這兩個層有什麼區別?Channel和server又有什麼區別?
 
 
 
-> final Registry registry = getRegistry(originInvoker); // 獲取註冊中心對象
 -> final URL registedProviderUrl = getRegistedProviderUrl(originInvoker); //獲取服務提供者URL
-> register(registryUrl, registedProviderUrl); // 向註冊中心註冊
這幾步在12 - 註冊中心 Zookeeper中詳細講解
 
 
 
 -> final URL overrideSubscribeUrl = getSubscribedOverrideUrl(registedProviderUrl); //創建監聽配置規則URL
 -> final OverrideListener overrideSubscribeListener = newOverrideListener(overrideSubscribeUrl, originInvoker); //創建監聽器
-> registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener); //註冊監聽器
訂閱在11 - 註冊中心中講解
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章