dubbo源碼—service export

在應用編寫好服務並進行以後,dubbo負責將服務export出去,dubbo export服務的時候主要作了如下幾件事:java

  • 將服務export到本地(根據scope的配置)
  • 建立Invoker(啓動本地NettyServer,監聽指定端口,等待請求)
  • 註冊provider的信息到registry,供consumer發現並訂閱服務
  • 訂閱registry中的configurator節點,能夠動態更改部分provider的配置

暴露服務的配置方式有:spring

  • 直接經過API方式
  • 經過xml配置
  • 經過註解

ServiceBean加載和初始化

以經常使用的xml配置爲例,前面說了dubbo的xml自定義標籤最後都是將對應的bean注入容器中,<dubbo:service /> 對應的就是ServiceBean,service暴露服務就在spring初始化ServiceBean的時候網絡

<dubbo:service interface="com.test.service.TestDubboService" ref="testDubboServiceImpl"/>

dubbo解析xml會將對應的bean—ServiceBean注入到spring容器中,因爲解析xml的時候配置的bean是非lazyInit的,因此在spring容器初始化完成以後,會初始化全部非lazyInit的bean。app

在spring容器初始化後,會廣播ContextRefreshedEvent事件通知,ServiceBean實現了ApplicationListener,在收到該事件以後調用export方法框架

// AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
  // Instantiate all remaining (non-lazy-init) singletons.
  finishBeanFactoryInitialization(beanFactory);
  
  // Last step: publish corresponding event.
  // 裏面會廣播ContextRefreshedEvent事件
  finishRefresh();
}

// ServiceBean
public void onApplicationEvent(ApplicationEvent event) {
  // 在容器初始化完成以後收到ContextRefreshedEvent事件,開始export服務
  if (ContextRefreshedEvent.class.getName().equals(event.getClass().getName())) {
    if (isDelay() && ! isExported() && ! isUnexported()) {
      if (logger.isInfoEnabled()) {
        logger.info("The service ready on spring started. service: " + getInterface());
      }
      export();
    }
  }
}

服務export從ServiceConfig#export開始jvm

  1. export:判斷是不是延遲啓動,若是是延遲啓動則啓動守護線程,sleep指定時間以後再調用doExport,不然直接調用
  2. doExport:主要工做是檢查並配置
    1. 初始化application、registries、monitor等配置
    2. 判斷是不是泛化調用,若是不是,判斷interface和ref是否合法
    3. 檢查並配置application、registries、protocols、ServiceConfig自己,找對應配置類屬性的set方法,依次從System.getProperty(-D參數指定,或者set進去的配置)、dubbo.properties.file參數執行的配置文件文件中查找對應的屬性,而後調用set 方法配置
    4. 檢查是否有stub和mock配置,若是有配置,判斷配置是否合法。若是有stub配置:判斷stub類是否有該服務interface類型的構造方法;若是有mock配置:若是直接是"return"表達式,parse返回的value是否合法,不然須要判斷mockClass是否有無參的構造方法
  3. loadRegistries:加載全部的registries,可能會有多個註冊中心,查找全部的registries配置並返回符合條件的
    1. 針對每個registry配置,從applicationConfig、registryConfig獲取參數拼裝registryUrl
    2. 條件是:若是是provider則register不能配置爲false(能夠不配置,若是配置了必須爲true);若是不是provider,subscribe不能配置爲false(能夠不配置,若是配置了必須爲true)。
  4. doExportUrls:因爲dubbo支持多個協議,因此dubbo針對每一種協議都會在每個註冊中心註冊一遍
  5. doExportUrlsFor1Protocol:根據配置來拼裝URL,在export的整個過程當中靠URL來傳遞配置
    1. 獲取配置的協議名稱,若是沒有配置協議名稱,則使用默認協議:dubbo
    2. 獲取配置的ip:port,若是port沒有配置從默認端口20880開始依次向後尋找可用的port,若是port配置爲-1表示隨機選取一個port
    3. 從application、module、provider、ptotocol等獲取配置,將這些配置加入到map中未來用來生成URL
    4. 判斷是否有dubbo:argument配置,將對應的配置也加入map
    5. 是不是泛化(Generic)調用,若是沒有則判斷是否有method級的配置
    6. 是不是injvm的調用,若是是,則不須要註冊到註冊中心
    7. 根據前面host:port、protocolName、map構造URL
    8. 判斷scope的配置,爲none表示不暴露服務,配置爲remote則export到local和remote,若是配置爲local則只export到local

export服務到本地

若是scope沒有配置或者配置local、remote,dubbo會將服務export到本地,意思就是:將服務以injvm協議export出去,若是是同一個jvm的應用能夠直接經過jvm發起調用,而不須要經過網絡發起遠程調用。ide

export到本地主要作了如下幾件事:ui

  1. 將url的協議配置爲jvm,host:port配置爲127.0.0.1:0
  2. 構造filter鏈,雖然是本地export,可是會通過定義好的filter
  3. 構造InjvmExporter

建立Invoker

若是scope沒有配置或者配置remote,dubbo會建立invoker,建立invoker的時候會啓動NettyServer,監聽指定的端口等待consumer請求。在dubbo中provider和consumer端都會有Invoker,實現的是同一個接口,可是不一樣的實現,invoker的意義就是服務的代理,provider側的invoker就是提供服務的可執行體,在netty接收到請求以後會經過invoker來處理,最後調用目標服務。url

建立invoker並啓動NettyServer的調用堆棧線程

export的主要過程是:

  1. 建立Invoker,proxyFactory.getInvoker
  2. 建立filter鏈,ProtocolFilterWrapper#buildInvokerChain
  3. 調用配置的exporter的listener,ListenerExporterWrapper#ListenerExporterWrapper
  4. 啓動NettyServer,DubboProtocol#openServer

filter和listener是可擴展的,能夠本身實現filter和listener,按照SPI方式配置好,dubbo會自動加載。

註冊到註冊中心並訂閱

前面只是完成service的啓動並具有可被請求的狀態,可是dubbo做爲一個支持服務自發現的框架,還會把provider的信息註冊到registry,而且訂閱configurators。

註冊的調用堆棧是

註冊和訂閱主要邏輯在RegistryProtocol#export

  1. 啓動NettyServer
  2. 註冊providerUrl
  3. 訂閱configurators

registry就是一個目錄服務,註冊的過程也就是建立對應的目錄,並訂閱關心的目錄變化。provider會在registry中建立相似以下的目錄結構

其中provider註冊的url爲,會建立com.foo.BarService、provider和providerUrl節點

dubbo/com.test.service.TestDubboService/providers/dubbo%3A%2F%2F192.168.0.102%3A20880%2Fcom.test.service.TestDubboService%3Fapplication%3Dcom.test.demo%26default.export%3Dtrue%26export%3Dtrue%26generic%3Dfalse%26interface%3Dcom.test.service.TestDubboService%26pid%3D45599%26side%3Dprovider%26timestamp%3D1515313385792

接下來會建立並訂閱configurators節點,訂閱的意思就是監聽configurators及其子節點,建立configurators的時候會添加listener,provider端監聽configurators的listener是:

com.alibaba.dubbo.registry.integration.RegistryProtocol.OverrideListener#notify

在治理中心中修改provider的配置的時候,註冊中心會通知監聽的listener,provider會進行相關配置。

總結

export服務是dubbo關鍵路徑中的第一步,此時dubbo已經具有了被consumer自動發現並調用的條件,接下來就是consumer發現服務。

相關文章
相關標籤/搜索