本節主要闡述如下兩個問題: 1、Dubbo自定義標簽實現。 2、dubbo通過Spring載入配置文件後,是如何觸發註冊中心、服務提供者、服務消費者按照Dubbo的設計執行相關的功能。 ...
本節主要闡述如下兩個問題:
1、Dubbo自定義標簽實現。
2、dubbo通過Spring載入配置文件後,是如何觸發註冊中心、服務提供者、服務消費者按照Dubbo的設計執行相關的功能。
所謂的執行相關功能如下:
1)註冊中心啟動,監聽消息提供者的註冊服務、接收消息消費者的服務訂閱(服務註冊與發現機制)。
2)服務提供者向註冊中心註冊服務。
3)服務消費者向註冊中心訂閱服務。
接下來從使用dubbo的角度,從配置文件入手:
1、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應用程式名、註冊中心、協議、服務提供者參數預設值、服務提供者,這些配置後面的實現原理是什麼呢?是如何啟動併發揮相關作用的呢?
2、Spring自定義標簽即命令空間實現
dubbo自定義標簽與命名空間其實現代碼在模塊dubbo-config中,其核心實現如下:
2.1 DubboNamespaceHandler
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(基於註解),下文會詳細分析上述兩個解析類的實現。
2.2 定義dubbo.xsd 文件
在dubbo-config-spring模塊下的 src/main/resouce/META-INF中分別定義dubbo.xsd、spring.handlers、spring.schemas。
關於Spring如何新增命名空間與標簽,在源碼分析ElasticJob時已經詳細介紹過,再這裡就不做 過多重覆,如需瞭解,請查看:https://blog.csdn.net/prestigeding/article/details/79751023
3、Bean解析機制(Spring基礎知識)
我們應該知道,Spirng的配置支持xml配置文件與註解的方式,故Dubbo也支持兩種配置方式,xml與註解方式。
3.1 xml配置方式解析
BeanDefinitionParser:Spring定義的bean解析器,要實現自定義標簽,則需要實現該介面,然後通過NamespaceHandlerSupport將Bean定義解析器註冊到Spring bean解析器中。從介面中可以看出,其終極目標就是將Element element(xml節點)解析成BeanDefinition,有關於Spring BeanDefinition,請參考:https://mp.csdn.net/mdeditor/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。
1)如果name屬性不為空,則取name的值,如果已存在,則為 name + 序號,例如 name,name1,name2。
2)如果name屬性為空,如果是dubbo:protocol標簽,則取protocol屬性,其他的則取interface屬性,如果不為空,則取該值,但如果已存在,和name處理相同,在後面追加序號。
3)如果第二步還未空,則取beanClass的名稱,如果已存在,則追加序號。
Step2:根據不同的標簽解析特殊屬性。
1)dubbo:protocol,添加protocol屬性(BeanDefinition)。
2)dubbo:service,添加ref屬性。
3)dubbo:provider,嵌套解析,dubbo:provider標簽有兩個可選的子標簽,dubbo:service、dubbo:parameter,這裡需要嵌套解析dubbo:service標簽
知識點:
dubbo:provider是配置服務提供者的預設參數,在dubbo spring配置文件中可以配置多個dubbo:provider,那dubbo:service標簽如何選取一個合適的dubbo:provider作為其預設參數
呢?有兩種辦法,其一:將dubbo:service標簽直接聲明在dubbo:provider方法,其二,在dubbo:service中通過provider屬性指定一個provider配置,如果不填,並且存在多個dubbo:provider配置,則會拋出錯誤。
provider配置。
4)dubbo:customer:解析嵌套標簽,其原理與dubbo:provider解析一樣。
Step3:解析標簽,將屬性與值填充到BeanDefinition的propertyValues中。
最終返回BeanDefinition實例,供Spring實例化Bean。
上述已經解答了Dubbo自定義標簽的解析實現,其實就完成了ApplicationConfig、RegistryConfig、ServiceBean、ReferenceBean實例的初始化,那什麼時候構建與註冊中心的連接、服務提供者什麼時候會向註冊中心註冊服務,服務消費者向註冊中心訂閱服務呢?
通過上述步驟,我們已經知道已經成功解析註冊中心、服務提供者、服務消費者的配置元信息,並將其實例化,按照我們的思路,配置對象生成後,下一步應該是實現Dubbo服務的註冊與發現機制,但代碼中無法找到相關代碼。
據我目前所掌握的知識,Spring在對象實例化,一般有兩種方式來對Bean做一些定製化處理。
1、實現BeanPostProcessor Spring後置處理器,在Bean初始化前後執行相關操作。
2、Bean實現InitializingBean介面(init-method)
瀏覽表格中所有Bean的聲明,發現了兩個類非常特殊:
ServiceBean(服務提供者)與ReferenceBean(服務消費者)比較特殊,實現了Spring與Bean生命周期相關的介面。
InitializingBean,其聲明的介面為afterPropertiesSet方法,顧名思義,就是在bean初始化所有屬性之後調用。
DisposableBean:其聲明的介面為destroy()方法,在Spring BeanFactory銷毀一個單例實例之前調用。
ApplicationContextAware:其聲明的介面為void setApplicationContext(ApplicationContext applicationContext),實現了該介面,Spring容器在初始化Bean時會調用該方法,註入ApplicationContext,已方便該實例可以直接調用applicationContext獲取其他Bean。
ApplicationListener:容器重新刷新時執行事件函數。
BeanNameAware:其聲明的介面為:void setBeanName(String name),實現該介面的Bean,其實例可以獲取該實例在BeanFactory的id或name。
FactoryBean:Spring初始化Bean的另外一種方式,例如dubbo:reference,需要返回的對象並不是ReferenceBean,而是要返回ref指定的代理類來執行業務操作,故這裡使用FactoryBean非常合適,FactoryBean定義瞭如下三個方法:
1)T getObject() throws Exception:獲取需要返回的結果對象。
2)Class
推薦內容:https://www.roncoo.com/course/list.html?courseName=Dubbo
文章來源:https://blog.csdn.net/prestigeding/article/details/80490338