朝花夕拾---dubbo源碼分析-創(chuàng)新互聯(lián)

前言

該篇博客意在做dubbo啟動(dòng)調(diào)用流程做源碼分析,采用先給出部分結(jié)論,然后推導(dǎo)出整個(gè)調(diào)用流程的過程

創(chuàng)新互聯(lián)公司專業(yè)為企業(yè)提供李滄網(wǎng)站建設(shè)、李滄做網(wǎng)站、李滄網(wǎng)站設(shè)計(jì)、李滄網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)與制作、李滄企業(yè)網(wǎng)站模板建站服務(wù),十載李滄做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。一? 服務(wù)發(fā)布

dubbo服務(wù)的每個(gè)標(biāo)記了@service的類和在xml配置中帶有標(biāo)簽,均會(huì)被解析成ServiceBean,服務(wù)發(fā)布的故事就從serviceBean這個(gè)類開始

首先看一下serviceBean的類繼承關(guān)系:

從類繼承圖中,我們發(fā)現(xiàn)了幾個(gè)重要的接口:

serviceConfig? ? ? ?這個(gè)是和dubbo服務(wù)發(fā)布相關(guān)的

ApplicationListener? ? spring的事件相關(guān)

InitializingBean? ? ? ?初始化相關(guān)

當(dāng)然最重要的就是ApplicationListener的監(jiān)聽方法了:

以下是服務(wù)發(fā)布的幾個(gè)重要路徑:

ServiceBean#export();

ServiceConfig#doExport()

doExportUrlsFor1Protocol()

在doExportUrlsFor1Protocol這里就是服務(wù)發(fā)布的重點(diǎn)了

以上截圖就是dubbo在做服務(wù)發(fā)布的核心代碼了,這里dubbo使用了動(dòng)態(tài)代理(SPI)+裝飾器模式,完整的構(gòu)造了一個(gè)Invoker和Exporter

DUBBO的SPI:ExtensionLoader? 通過加載指定路徑下,配置的key-value形式的類。同時(shí)還支持代理和增強(qiáng)(Wrapper + 裝飾),有興趣的同學(xué)可以認(rèn)真研究一下dubbo的SPI機(jī)制,這里只做簡單概括,比如里面2個(gè)最重要的代理對(duì)象:proxyFacotory,protocol,他們的源碼分別截圖如下:

proxyFactory:

protocol:

從以上截圖不難發(fā)現(xiàn):protocol和proxyFactory的處理邏輯大體類似:通過url獲取指定參數(shù),如果為空,就使用默認(rèn)值:然后通過ExtensionLoader加載從url中獲取的對(duì)象

首先看一下通過proxyFactory獲取的Invoker對(duì)象:

想一下,為什么extName是javassist,獲取到的ProxyFactory卻是:StubProxyFactoryWrapper?按照之前說的SPI機(jī)制,應(yīng)該獲取的是:JavassistProxyFactory?

這是因?yàn)椋涸贓xtensionLoader#createExtension時(shí)

cachedWrapperClasses的寫入是在讀取指定路徑的文件時(shí)寫入的,通過判斷加載的類是否有,包含相同接口的構(gòu)造器做判斷的:

這里真正干活的還是:JavassistProxyFactory

所以,真正構(gòu)建Invoker的代碼如下:

其實(shí)就是構(gòu)建了一個(gè)AbstractProxyInvoker,其中的Wrapper簡單的理解成一個(gè)包裝類即可(這就是dubbo動(dòng)態(tài)生成類的方式,其實(shí)沒有什么多大的技術(shù)問題,只是覺得就是裝X而已),代碼如下:

再來看看export過程:

同樣的,extName是registry,實(shí)際的加載類是:ProtocolListenerWrapper

而ProtocolListenerWrapper里面包裝的protocol是:ProtocolFilterWrapper,而ProtocolFilterWrapper里面包裝的protocol是RegistryProtocol(真正干活的)

可以看下最終生成的Exporter的結(jié)構(gòu):

其中DubboExporter是在DubboProtocol類中構(gòu)造的,還是和之前一樣,通過裝飾器,一層一層遞進(jìn)構(gòu)造的:

至此,服務(wù)的發(fā)布已經(jīng)完成,其中有些步驟跳躍可能稍微大一點(diǎn),感興趣的同學(xué)請(qǐng)自行本地調(diào)試?

二? 服務(wù)調(diào)用

dubbo中每一個(gè)標(biāo)記了@Reference域和在xml中配置了的元素,均會(huì)被解析成一個(gè)ReferenceBean

首先,看一下ReferenceBean的類關(guān)系:

其中FactoryBean就是spring的工廠Bean,和ServiceBean類似,ReferenceBean也繼承一個(gè)Config類,如上,服務(wù)調(diào)用的故事就從ReferenceConfig的#get()開始

ReferenceBean#getObject()

? ReferenceConfig#get()

init();

相信使用過動(dòng)態(tài)代理的同學(xué)都知道,使用動(dòng)態(tài)代理的使用,通過代理對(duì)象,在自己的邏輯里面就可以"為所欲為"了。dubbo在服務(wù)調(diào)用的時(shí)候也是這么干的!

init方法就是創(chuàng)建代理的入口,方法比較長,咱們撿重點(diǎn)說,前面就是一些校驗(yàn),判斷,最主要的方法入口:

創(chuàng)建代理需要一個(gè)map,看看這個(gè)map里面的信息如下:

下面正式開啟創(chuàng)建代理的過程,老規(guī)矩,忽略掉無關(guān)精要的代碼,直接上干貨:

這個(gè)refprotocol就是在前面截圖的那個(gè)Protocol$Adaptive代碼,這里咱們?yōu)榱朔奖阏{(diào)試,直接把代碼替換一下:

和服務(wù)發(fā)布過程一樣,extName是registry,獲取到的實(shí)例卻是:ProtocolListenerWrapper(裝飾器模式)

大概裝飾層級(jí)就是:

ProtocolListenerWrapper

?ProtocolFilterWrapper

RegistryProtocol

在RegistryProtocol是真正干活的地方:

一路debug調(diào)試,最終返回到創(chuàng)建代理的代碼入口:

在之前的服務(wù)發(fā)布過程中,我們已經(jīng)帖出了proxyFactory的相關(guān)代碼(dubbo這里做了動(dòng)態(tài)加載,不利于調(diào)試,咱們做個(gè)替換)

替換后的代碼如下:

現(xiàn)在將要進(jìn)行真正的動(dòng)態(tài)代理的創(chuàng)建過程:

和其他的Adaptive一樣,真正干活的是JavassistProxyFactory,使用StubProxyFactoryWrapper做裝飾

真正干活的是JavassistProxyFactory

看到這里,熟悉動(dòng)態(tài)代理的同學(xué)已經(jīng)很熟悉了。真正的執(zhí)行邏輯就在InvokerInvocationHandler里面了,在這個(gè)handler里面是不是為所欲為呢?

截圖如下:

由截圖可知,在InvokerInvocationHandler里面真正調(diào)用就是使用invoker調(diào)用邏輯

當(dāng)真正調(diào)用時(shí),一路dubug

這個(gè)Invoker也是一個(gè)裝飾器。咱們一步一步調(diào)試進(jìn)入:

首先:MockClusterInvoker

真正的調(diào)用又委托給了:FailoverClusterInvoker

從以上代碼注釋中可以看出,F(xiàn)ailoverClusterInvoker,通過負(fù)載均衡器選擇"最優(yōu)"的Invoker發(fā)起遠(yuǎn)程調(diào)用

這里選擇了:RegistryDirectory$DeleteInvoker其實(shí)就是一個(gè)InvokerWrapper

真正干活的是ListenerInvokerWrapper

繼續(xù)遞進(jìn):調(diào)用ProtocolFilterWrapper

最終來到了ProtocolFilterWrapper的匿名內(nèi)部類:

把調(diào)用過程委托給了filter調(diào)用鏈路,至此,Invoker的使命完成了。相信更深的調(diào)用邏輯,通過分析Filter就能找到答案了

三? FailOverClusterInvoker選擇Invoker過程既FilterChain調(diào)用鏈的組裝

在第二節(jié)中,有分析服務(wù)發(fā)布調(diào)用過程,最紅是委托給了Filter調(diào)用。我們?cè)诜治龅臅r(shí)候,有意的忽略掉了部分調(diào)用細(xì)節(jié),只是為了更好的梳理出整個(gè)調(diào)用鏈路。下面就分析一下在負(fù)載均衡器選擇Invoker的詳細(xì)邏輯

故事的開始當(dāng)然是從FailoverClusterInvoker的invoke開始,FailoverClusterInvoker沒有自己實(shí)現(xiàn)invoke,其父類AbstractClusterInvoker實(shí)現(xiàn)了:

尋找Invoker的時(shí)候委托給了RegistryDirectory:

最終的Invoker尋找在RegistryDirectory里面維護(hù)的一個(gè)字段:methodInvokerMap里面查詢即可

查詢到全量的數(shù)據(jù)之后,就通過負(fù)載均衡器選擇,完成Invoker的選擇

那RegistryDirectory的methodInvokerMap又是在什么時(shí)候獲得調(diào)用方法和Invoker的對(duì)應(yīng)關(guān)系的呢?

通過跟蹤字段的調(diào)用來源

最終確認(rèn): RegistryProtocol#doRefer時(shí)會(huì)調(diào)用到如上方法里面,生成method和Invokers的對(duì)應(yīng)關(guān)系

以上,將服務(wù)發(fā)布,服務(wù)調(diào)用的過程做了較為粗略和完整的說明

四 結(jié)論證明

在前言部分有說過,先給出部分結(jié)論:

1 所有被標(biāo)記了@service和使用標(biāo)記的元素,均會(huì)被spring解析成ServiceBean

2 所有被標(biāo)記了@Reference和使用的元素,均會(huì)被spring解析成ReferenceBean

這是怎么做到的呢?

在結(jié)合xml使用的時(shí)候,dubbo有引入DubboNamespaceHandler,該handler會(huì)解析相關(guān)的xml標(biāo)簽,完成如上功能:

而在springboot應(yīng)用中,dubbo有引入:ServiceAnnotationBeanPostProcessor

該類是一個(gè)前置處理器,會(huì)掃描@service標(biāo)記的類,通過構(gòu)建BeanDefinitionBuilder完成ServiceBean的注冊(cè):

同樣的:springboot應(yīng)用中引入了ReferenceAnnotationBeanPostProcessor

ReferenceAnnotationBeanPostProcessor是一個(gè)后置處理器,在Bean初始化時(shí)會(huì)被調(diào)用,注入相應(yīng)的代理類

創(chuàng)作不易,如果對(duì)你有幫助,請(qǐng)點(diǎn)贊+收藏!

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧

文章名稱:朝花夕拾---dubbo源碼分析-創(chuàng)新互聯(lián)
分享網(wǎng)址:http://www.muchs.cn/article42/deoghc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供小程序開發(fā)電子商務(wù)、網(wǎng)頁設(shè)計(jì)公司、App開發(fā)、網(wǎng)站排名、虛擬主機(jī)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都app開發(fā)公司