該篇博客意在做dubbo啟動調用流程做源碼分析,采用先給出部分結論,然后推導出整個調用流程的過程
創(chuàng)新互聯公司專業(yè)為企業(yè)提供李滄網站建設、李滄做網站、李滄網站設計、李滄網站制作等企業(yè)網站建設、網頁設計與制作、李滄企業(yè)網站模板建站服務,十載李滄做網站經驗,不只是建網站,更提供有價值的思路和整體網絡服務。一? 服務發(fā)布dubbo服務的每個標記了@service的類和在xml配置中帶有標簽
首先看一下serviceBean的類繼承關系:
從類繼承圖中,我們發(fā)現了幾個重要的接口:
serviceConfig? ? ? ?這個是和dubbo服務發(fā)布相關的
ApplicationListener? ? spring的事件相關
InitializingBean? ? ? ?初始化相關
當然最重要的就是ApplicationListener的監(jiān)聽方法了:
以下是服務發(fā)布的幾個重要路徑:
ServiceBean#export();
ServiceConfig#doExport()
doExportUrlsFor1Protocol()
在doExportUrlsFor1Protocol這里就是服務發(fā)布的重點了
以上截圖就是dubbo在做服務發(fā)布的核心代碼了,這里dubbo使用了動態(tài)代理(SPI)+裝飾器模式,完整的構造了一個Invoker和Exporter
DUBBO的SPI:ExtensionLoader? 通過加載指定路徑下,配置的key-value形式的類。同時還支持代理和增強(Wrapper + 裝飾),有興趣的同學可以認真研究一下dubbo的SPI機制,這里只做簡單概括,比如里面2個最重要的代理對象:proxyFacotory,protocol,他們的源碼分別截圖如下:
proxyFactory:
protocol:
從以上截圖不難發(fā)現:protocol和proxyFactory的處理邏輯大體類似:通過url獲取指定參數,如果為空,就使用默認值:然后通過ExtensionLoader加載從url中獲取的對象
首先看一下通過proxyFactory獲取的Invoker對象:
想一下,為什么extName是javassist,獲取到的ProxyFactory卻是:StubProxyFactoryWrapper?按照之前說的SPI機制,應該獲取的是:JavassistProxyFactory?
這是因為:在ExtensionLoader#createExtension時
cachedWrapperClasses的寫入是在讀取指定路徑的文件時寫入的,通過判斷加載的類是否有,包含相同接口的構造器做判斷的:
這里真正干活的還是:JavassistProxyFactory
所以,真正構建Invoker的代碼如下:
其實就是構建了一個AbstractProxyInvoker,其中的Wrapper簡單的理解成一個包裝類即可(這就是dubbo動態(tài)生成類的方式,其實沒有什么多大的技術問題,只是覺得就是裝X而已),代碼如下:
再來看看export過程:
同樣的,extName是registry,實際的加載類是:ProtocolListenerWrapper
而ProtocolListenerWrapper里面包裝的protocol是:ProtocolFilterWrapper,而ProtocolFilterWrapper里面包裝的protocol是RegistryProtocol(真正干活的)
可以看下最終生成的Exporter的結構:
其中DubboExporter是在DubboProtocol類中構造的,還是和之前一樣,通過裝飾器,一層一層遞進構造的:
至此,服務的發(fā)布已經完成,其中有些步驟跳躍可能稍微大一點,感興趣的同學請自行本地調試?
二? 服務調用dubbo中每一個標記了@Reference域和在xml中配置了
首先,看一下ReferenceBean的類關系:
其中FactoryBean就是spring的工廠Bean,和ServiceBean類似,ReferenceBean也繼承一個Config類,如上,服務調用的故事就從ReferenceConfig的#get()開始
ReferenceBean#getObject()
? ReferenceConfig#get()
init();
相信使用過動態(tài)代理的同學都知道,使用動態(tài)代理的使用,通過代理對象,在自己的邏輯里面就可以"為所欲為"了。dubbo在服務調用的時候也是這么干的!
init方法就是創(chuàng)建代理的入口,方法比較長,咱們撿重點說,前面就是一些校驗,判斷,最主要的方法入口:
創(chuàng)建代理需要一個map,看看這個map里面的信息如下:
下面正式開啟創(chuàng)建代理的過程,老規(guī)矩,忽略掉無關精要的代碼,直接上干貨:
這個refprotocol就是在前面截圖的那個Protocol$Adaptive代碼,這里咱們?yōu)榱朔奖阏{試,直接把代碼替換一下:
和服務發(fā)布過程一樣,extName是registry,獲取到的實例卻是:ProtocolListenerWrapper(裝飾器模式)
大概裝飾層級就是:
ProtocolListenerWrapper
?ProtocolFilterWrapper
RegistryProtocol
在RegistryProtocol是真正干活的地方:
一路debug調試,最終返回到創(chuàng)建代理的代碼入口:
在之前的服務發(fā)布過程中,我們已經帖出了proxyFactory的相關代碼(dubbo這里做了動態(tài)加載,不利于調試,咱們做個替換)
替換后的代碼如下:
現在將要進行真正的動態(tài)代理的創(chuàng)建過程:
和其他的Adaptive一樣,真正干活的是JavassistProxyFactory,使用StubProxyFactoryWrapper做裝飾
真正干活的是JavassistProxyFactory
看到這里,熟悉動態(tài)代理的同學已經很熟悉了。真正的執(zhí)行邏輯就在InvokerInvocationHandler里面了,在這個handler里面是不是為所欲為呢?
截圖如下:
由截圖可知,在InvokerInvocationHandler里面真正調用就是使用invoker調用邏輯
當真正調用時,一路dubug
這個Invoker也是一個裝飾器。咱們一步一步調試進入:
首先:MockClusterInvoker
真正的調用又委托給了:FailoverClusterInvoker
從以上代碼注釋中可以看出,FailoverClusterInvoker,通過負載均衡器選擇"最優(yōu)"的Invoker發(fā)起遠程調用
這里選擇了:RegistryDirectory$DeleteInvoker其實就是一個InvokerWrapper
真正干活的是ListenerInvokerWrapper
繼續(xù)遞進:調用ProtocolFilterWrapper
最終來到了ProtocolFilterWrapper的匿名內部類:
把調用過程委托給了filter調用鏈路,至此,Invoker的使命完成了。相信更深的調用邏輯,通過分析Filter就能找到答案了
三? FailOverClusterInvoker選擇Invoker過程既FilterChain調用鏈的組裝在第二節(jié)中,有分析服務發(fā)布調用過程,最紅是委托給了Filter調用。我們在分析的時候,有意的忽略掉了部分調用細節(jié),只是為了更好的梳理出整個調用鏈路。下面就分析一下在負載均衡器選擇Invoker的詳細邏輯
故事的開始當然是從FailoverClusterInvoker的invoke開始,FailoverClusterInvoker沒有自己實現invoke,其父類AbstractClusterInvoker實現了:
尋找Invoker的時候委托給了RegistryDirectory:
最終的Invoker尋找在RegistryDirectory里面維護的一個字段:methodInvokerMap里面查詢即可
查詢到全量的數據之后,就通過負載均衡器選擇,完成Invoker的選擇
那RegistryDirectory的methodInvokerMap又是在什么時候獲得調用方法和Invoker的對應關系的呢?
通過跟蹤字段的調用來源
最終確認: RegistryProtocol#doRefer時會調用到如上方法里面,生成method和Invokers的對應關系
以上,將服務發(fā)布,服務調用的過程做了較為粗略和完整的說明
四 結論證明在前言部分有說過,先給出部分結論:
1 所有被標記了@service和使用
2 所有被標記了@Reference和使用
這是怎么做到的呢?
在結合xml使用的時候,dubbo有引入DubboNamespaceHandler,該handler會解析相關的xml標簽,完成如上功能:
而在springboot應用中,dubbo有引入:ServiceAnnotationBeanPostProcessor
該類是一個前置處理器,會掃描@service標記的類,通過構建BeanDefinitionBuilder完成ServiceBean的注冊:
同樣的:springboot應用中引入了ReferenceAnnotationBeanPostProcessor
ReferenceAnnotationBeanPostProcessor是一個后置處理器,在Bean初始化時會被調用,注入相應的代理類
創(chuàng)作不易,如果對你有幫助,請點贊+收藏!
你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網查看詳情吧
文章名稱:朝花夕拾---dubbo源碼分析-創(chuàng)新互聯
分享網址:http://jinyejixie.com/article42/deoghc.html
成都網站建設公司_創(chuàng)新互聯,為您提供小程序開發(fā)、電子商務、網頁設計公司、App開發(fā)、網站排名、虛擬主機
聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯