本節主要闡述以下兩個問題:spring
所謂的執行相關功能以下:api
接下來從使用dubbo的角度,從配置文件入手:架構
<!-- 提供方應用信息,用於計算依賴關係 --> <dubbo:application name="uop" owner="uce" /> <!-- 使用zookeeper註冊中心暴露服務地址 --> <dubbo:registry protocol="zookeeper" address="zookeeper://192.168.xx.xx:2181?backup=192.168.xx.xx:2182,192.168.xx.xx:2183" /> <!--dubbox中引入Kryo和FST這兩種高效Java序列化實現,來逐步取代原生dubbo中的hessian2,若是使用kryo記得添加依賴 --> <dubbo:protocol name="dubbo" serialization="kryo" port="20990" /> <!-- 定義服務提供者默認屬性值 --> <dubbo:provider timeout="5000" threadpool="fixed" threads="100" accepts="1000" token="true" /> <!-- 暴露服務接口 一個服務能夠用多個協議暴露,一個服務也能夠註冊到多個註冊中心--> <!--Provider上儘可能多配置Consumer端的屬性,讓Provider實現者一開始就思考Provider服務特色、服務質量的問題--> <dubbo:service interface="com.yingjun.dubbox.api.UserService" ref="userService" />
上面經過dubbo提供的dubbo:application、dubbo:registry、dubbo:protocol、dubbo:provider、dubbo:service分別定義dubbo應用程序名、註冊中心、協議、服務提供者參數默認值、服務提供者,這些配置後面的實現原理是什麼呢?是如何啓動併發揮相關做用的呢?併發
dubbo自定義標籤與命名空間其實現代碼在模塊dubbo-config中,其核心實現以下。app
dubbo命名空間實現handler,其全路徑:com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler,其源碼實現以下:分佈式
public class DubboNamespaceHandler extends NamespaceHandlerSupport { static { Version.checkDuplicate(DubboNamespaceHandler.class); } @Override 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 AnnotationBeanDefinitionParser()); } }
從這裏能夠看出,dubbo自定義的標籤主要包括:application、module、registry、monitor、provider、consumer、protocol、service、reference、annotation,其具體解析實現類主要包括:DubboBeanDefinitionParser(基於xml配置文件)、AnnotationBeanDefinitionParser(基於註解),下文會詳細分析上述兩個解析類的實現。ide
在dubbo-config-spring模塊下的 src/main/resouce/META-INF中分別定義dubbo.xsd、spring.handlers、spring.schemas。 關於Spring如何新增命名空間與標籤,在源碼分析ElasticJob時已經詳細介紹過,再這裏就不作 過多重複,如需瞭解,請查看:http://www.javashuo.com/article/p-pptkrtcg-hp.html函數
咱們應該知道,Spirng的配置支持xml配置文件與註解的方式,故Dubbo也支持兩種配置方式,xml與註解方式。高併發
BeanDefinitionParser:Spring定義的bean解析器,要實現自定義標籤,則須要實現該接口,而後經過NamespaceHandlerSupport將Bean定義解析器註冊到Spring bean解析器中。從接口中能夠看出,其終極目標就是將Element element(xml節點)解析成BeanDefinition,有關於Spring BeanDefinition,請參考:https://blog.csdn.net/prestigeding/article/details/80490206 DubboBeanDefinitionParser構造函數以下:源碼分析
public DubboBeanDefinitionParser(Class<!--?--> beanClass, boolean required) { this.beanClass = beanClass; this.required = required; }
beanClass:該xml標籤節點最終會被Spring實例化的類名。 required:該標籤的ID是否必須。 標籤名稱 |類名
| :-: | -: dubbo:application | ApplicationConfig dubbo:module | ModuleConfig dubbo:registry | RegistryConfig dubbo:monitor| MonitorConfig dubbo:provider | ProviderConfig dubbo:consumer| ConsumerConfig dubbo:protocol| ProtocolConfig dubbo:service| ServiceBean dubbo:reference | ReferenceBean 注,包名:com.alibaba.dubbo.config bean解析器的主要目的就是將上述標籤,解析成對應的BeanDifinition,以便Spring構建上述類的實例。 本節不拷貝DubboBeanDefinitionParser根據xml定義的標籤與屬性轉換成BeanDefinitionParser的每一行代碼,本節只給出其大致關鍵點。 Step1:解析id屬性,若是DubboBeanDefinitionParser對象的required屬性爲true,若是id爲空,則根據以下規則構建一個id。
若是name屬性不爲空,則取name的值,若是已存在,則爲 name + 序號,例如 name,name1,name2。
若是name屬性爲空,若是是dubbo:protocol標籤,則取protocol屬性,其餘的則取interface屬性,若是不爲空,則取該值,但若是已存在,和name處理相同,在後面追加序號。
若是第二步還未空,則取beanClass的名稱,若是已存在,則追加序號。
Step2:根據不一樣的標籤解析特殊屬性。
Step3:解析標籤,將屬性與值填充到BeanDefinition的propertyValues中。最終返回BeanDefinition實例,供Spring實例化Bean。
上述已經解答了Dubbo自定義標籤的解析實現,主要完成了ApplicationConfig、RegistryConfig、ServiceBean、ReferenceBean實例的初始化,那何時構建與註冊中心的鏈接、服務提供者何時會向註冊中心註冊服務,服務消費者向註冊中心訂閱服務呢?
經過上述步驟,咱們已經知道已經成功解析註冊中心、服務提供者、服務消費者的配置元信息,並將其實例化,按照咱們的思路,配置對象生成後,下一步應該是實現Dubbo服務的註冊與發現機制,但代碼中沒法找到相關代碼。
據我目前所掌握的知識,Spring在對象實例化,通常有兩種方式來對Bean作一些定製化處理。
瀏覽表格中全部Bean的聲明,發現了兩個類很是特殊:
ServiceBean(服務提供者)與ReferenceBean(服務消費者)比較特殊,實現了Spring與Bean生命週期相關的接口。
看到這裏,難免有一點小激動,彷佛已經摸到Dubbo服務註冊與發現機制(Dubbo服務提供者、Dubbo服務消費者、註冊中心的啓動流程入口點了,下一步就是分析ServiceBean、ReferenceBean的實現原理,試圖揭開Dubbo服務註冊與發現機制,該部份內容將在下一篇中詳細分析。
註解配置方式的解析入口類:AnnotationBeanDefinitionParser,也是基於Spring註解解析邏輯,這部分在將在將來《Spring系列進階篇-源碼分析註解解析實現原理》中詳細分析,目前暫未深究,讀者朋友們,若是有興趣,能夠以AnnotationBeanDefinitionParser爲入口,進行進一步的分析。
本節就講解到這裏了,下一篇將重點分析ServiceBean(服務提供者啓動流程)。
做者介紹:丁威,《RocketMQ技術內幕》做者,RocketMQ 社區佈道師,公衆號:中間件興趣圈 維護者,目前已陸續發表源碼分析Java集合、Java 併發包(JUC)、Netty、Mycat、Dubbo、RocketMQ、Mybatis等源碼專欄。能夠點擊連接:中間件知識星球,一塊兒探討高併發、分佈式服務架構,交流源碼。