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並返回。
我在網上找到這麼一個圖,顯示了載入的和解析的過程。