1. 程式人生 > >dubbo原始碼分析(一)-從xml到我們認識的Java物件

dubbo原始碼分析(一)-從xml到我們認識的Java物件

  專案中用的dubbo的挺多的,然後隨著自己對dubbo的慢慢深入,自己也希望能夠了解dubbo的底層實現,這半年來一直在看dubbo的原始碼,有點斷斷續續的,於是準備寫一個dubbo原始碼系列的分析文章,一來方便自己總結,二來也能夠讓自己的學習有輸出分享。
  整個系列會從dubbo的xml到bean到生產者啟動-註冊到消費者訂閱-呼叫的這一主線,然後會穿插一些相關的負載均衡、熔斷、過濾器、監控、spi等等。讓我們進入一個全新的世界吧,let's go
  1、如果你好奇為什麼配置了xml檔案dubbo就可以啟動,dubbo的配置檔案如何轉換為我們的Java中的物件的?
  2、想對spring中的自定義的標籤有所瞭解的。


  那麼本文特別適合你閱讀。
    首先,我們來看一下簡單的dubbo的provide的配置檔案,如下:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4 xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
 5 xsi:schemaLocation
="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans.xsd 7 http://code.alibabatech.com/schema/dubbo 8 http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> 9 <!-- 提供方應用資訊,用於計算依賴關係 --> 10 <dubbo:application name="demo-provider"/> 11 <!-- 使用zk廣播註冊中心暴露服務地址
--> 12 <dubbo:registry id="zk1" address="127.0.0.1:2181" protocol="zookeeper"/> 13 <!-- 用dubbo協議在20880埠暴露服務 --> 14 <dubbo:protocol id="mydubbo" name="dubbo" port="20880"/> 15 <!-- 宣告需要暴露的服務介面 --> 16 <dubbo:service interface="com.dubbo.DemoService" ref="demoService"/> 17 </beans>

  剛開始看的時候,我就很好奇dubbo怎麼識別這些,之前對spring的自定義標籤有一些瞭解,http://code.alibabatech.com/schema/dubbo,http://code.alibabatech.com/schema/dubbo/dubbo.xsd 這2行有一點吸引我們,開啟看看發現裡面定義了dubbo相關標籤的xsd,對於xsd不瞭解的同學自己查資料學習了哈,這裡不在做解釋。找到xsd檔案我們就知道要到spring.handlers檔案看看,開啟這個檔案看看:

1 http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler

發現貓膩了,這裡定義了http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler,其實這是一個鍵值對,那我們就看看DubboNamespaceHandler是幹嘛的:

public class DubboNamespaceHandler extends NamespaceHandlerSupport {

  static {
    Version.checkDuplicate(DubboNamespaceHandler.class);
  }

  public void init() {
    registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
    registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
    registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
    registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
    registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
    registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
    registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
    registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
    registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
    registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(AnnotationBean.class, true));
  }
}

  發現我們熟悉的dubbo標籤都在這裡,看名字registerBeanDefinitionParser就知道是註冊bean的解析了,原來dubbo的每個標籤都對應一個class,可以開啟每個class看看,發現都是每個標籤的屬性以及一些相關的處理,這裡就不在打開了,有init方法,應該是載入的時候呼叫init,到這裡可能就好奇了這個類是什麼時候載入的呢?聯想到spring.handlers裡面的東西,好像好多spring相關的都會有這麼一個東西,那我們找找spring怎麼載入解析spring.handlers的,我這裡基於大家都比較熟悉spring的bean載入過程了哈。
  直接定位到org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions方法:根據root解析節點

  1-2、判斷是不是預設的namespace;
  3、不是預設namespace就parseCustomElement解析節點;
  4、獲取namspaceUri,根據namspaceUri去獲取namespaceHandler,然後利用handler解析dubbo節點。

  1、獲取解析的節點的localname;
  2、根據localname去找BeanDefinitionParser,找到BeanDefinitionParser並返回。
  我在網上找到這麼一個圖,顯示了載入的和解析的過程。