Dubbo
整體架構(gòu)
1天揖、InvokerInvocationHandler jdk動(dòng)態(tài)代理
5夺欲、RegistryDirector返回Invokers
Router分為:Script 腳本路由、Condition 條件路由
6今膊、通過(guò)MockInvokersSelector的route方法(getNormalInvokers)拿到能正常執(zhí)行的invokers
8些阅、當(dāng)回到AbstractClusterInvoker后,執(zhí)行(默認(rèn)FailoverClusterInvoker斑唬,根據(jù)配置的是市埋,F(xiàn)ailfast Cluster(快速失敗),
Failsafe Cluster(失敗安全),
Failback Cluster(失敗自動(dòng)恢復(fù)),
Forking Cluster(并行調(diào)用多個(gè)服務(wù)器,只要一個(gè)成功即返回),
Broadcast Cluster(廣播調(diào)用所有提供者恕刘,逐個(gè)調(diào)用缤谎,任意一臺(tái)報(bào)錯(cuò)則報(bào)錯(cuò)))doInvoker方法
9、FailoverClusterInvoker調(diào)用AbstractClusterInvoker的select方法
10、執(zhí)行doSelect方法
11、調(diào)用AbstractLoadbalance的select方法
12斗躏、根據(jù)配置的負(fù)載均衡策略調(diào)用對(duì)應(yīng)的(如RoundRobinLoadBalance)類(lèi)的doSelect方法
13静汤、返回invokers.get()方法
14、調(diào)用FailoverClusterInvoker的invoke方法
- 在
Directory
中找出本次集群中的全部invokers
- 在
Router
中,將上一步的全部invokers
挑選出能正常執(zhí)行的invokers
- 在
LoadBalance
中,將上一步的能正常的執(zhí)行invokers
中,根據(jù)配置的負(fù)載均衡策略,挑選出需要執(zhí)行的invoker
Director接口
- StaticDirectory Invoker通過(guò)構(gòu)造函數(shù)傳入银择,所以不是動(dòng)態(tài)變化的,用的較少。
- RegistryDirectory 實(shí)現(xiàn)了NotifyListener接口姻政,notify方法就是注冊(cè)中心的回調(diào),可以根據(jù)注冊(cè)中心動(dòng)態(tài)變化
均繼承自抽象類(lèi)AbstractDirectory
Directory 代表多個(gè) Invoker岂嗓,可以把它看成 List<Invoker> ,但與 List 不同的是汁展,它的值可能是動(dòng)態(tài)變化的,比如注冊(cè)中心推送變更
Directory
獲取invoker
是從methodInvokerMap
中獲取的厌殉,主要都是讀操作,那它的寫(xiě)操作是在什么時(shí)候?qū)懙哪?就是在回調(diào)方法notify
的時(shí)候操作的食绿,也就是注冊(cè)中心有變化,則更新methodInvokerMap
和urlInvokerMap
的值
Router接口
- MockInvokersSelector
- ConditionRouter
- ScriptRouter
ScriptRouter:腳本路由規(guī)則 支持 JDK 腳本引擎的所有腳本,比如:javascript, jruby, groovy 等公罕,通過(guò) type=javascript 參數(shù)設(shè)置腳本類(lèi)型器紧,缺省為 javascript。
ConditionRouter(條件路由)
根據(jù)dubbo-admin配置的路由規(guī)則來(lái)過(guò)濾相關(guān)的invoker楼眷,當(dāng)我們對(duì)路由規(guī)則點(diǎn)擊啟用铲汪,就會(huì)觸發(fā)RegistryDirectory
類(lèi)的notify
方法。
notify方法調(diào)用refreshInvoker方法罐柳。
route方法的實(shí)現(xiàn)類(lèi)為ConditionRoute 根據(jù)條件進(jìn)行過(guò)濾
1掌腰、調(diào)用mathThen方法
2、調(diào)用matchCondition方法
3张吉、調(diào)用isMatch判斷
4齿梁、調(diào)用isMatchGlobPattern方法
Cluster
Cluster 將 Directory 中的多個(gè) Invoker 偽裝成一個(gè) Invoker,對(duì)上層透明,偽裝過(guò)程包含了容錯(cuò)邏輯勺择,調(diào)用失敗后创南,重試另一個(gè)
? 集群模塊是服務(wù)提供者和服務(wù)消費(fèi)者的中間層,為服務(wù)消費(fèi)者屏蔽了服務(wù)提供者的情況酵幕,這樣服務(wù)消費(fèi)者就可以專(zhuān)心處理遠(yuǎn)程調(diào)用相關(guān)事宜扰藕。比如發(fā)請(qǐng)求,接受服務(wù)提供者返回的數(shù)據(jù)等芳撒。這就是Dubbo Cluster集群的作用邓深。
<dubbo:service cluster="failsafe" />
通過(guò)cluster來(lái)指定集群容錯(cuò)方式
其實(shí)就是應(yīng)對(duì)出錯(cuò)情況采取的策略
- MergeableCluster 分組聚合 按組合并返回結(jié)果,用group區(qū)分笔刹,比如消費(fèi)者需要從每種group中調(diào)用一次返回結(jié)果芥备,合并結(jié)果返回。
- AvailableCluster 可用的舌菜,遍歷所有的Invokers萌壳,判斷isAvalible,只要一個(gè)有為true的直接調(diào)用返回日月,否則就拋出異常袱瓮。
- ForkingCluster 并行調(diào)用多個(gè)服務(wù)器,只要一個(gè)成功即返回
- FailfastCluster 快速失敗爱咬,只發(fā)起一次調(diào)用尺借,失敗立即報(bào)錯(cuò),通常用于非冪等性的寫(xiě)操作精拟,比如新增
- MockClusterWrapper 本地mock用于服務(wù)降級(jí)燎斩,如果服務(wù)提供方全部掛掉后,客戶(hù)端通過(guò)mock返回授權(quán)失敗
- FailoverCluster 失敗自動(dòng)切換蜂绎,當(dāng)出現(xiàn)失敗時(shí)重試其他服務(wù)器栅表,通常用于讀操作,可通過(guò)retries來(lái)設(shè)置重試次數(shù)师枣。所以如果是讀接口怪瓶,適合用FailoverCluster,如果是寫(xiě)接口践美,適合FailfastCluster
- FailbackCluster 失敗自動(dòng)恢復(fù)劳殖,后臺(tái)記錄失敗請(qǐng)求,定時(shí)重發(fā)拨脉,通常用于消息通知操作
- FailsafeCluster 失敗安全,出現(xiàn)異常時(shí)宣增,直接忽略玫膀,通常用于寫(xiě)入審計(jì)日志等操作。
- BroadcastCluster 廣播調(diào)用所有提供者爹脾,逐個(gè)調(diào)用帖旨,任意一臺(tái)報(bào)錯(cuò)則報(bào)錯(cuò)箕昭,通常用于通知所有提供者更新緩存或者日志等本地資源信息。
粘滯鏈接
用于有狀態(tài)服務(wù)解阅,盡可能讓客戶(hù)端總是向同一提供者發(fā)起調(diào)用落竹,除非提供者掛了,再連另一臺(tái)货抄,自動(dòng)開(kāi)啟延遲鏈接述召,以減少長(zhǎng)接數(shù)
<dubbo:referenc id="xxxService" interface="com.xxx.xxx" sticky="true"
LoadBalance
- RandomLoadBalance 隨機(jī) 按權(quán)重設(shè)置隨機(jī)概率
- RoundRobinLoadBalance 輪詢(xún),按權(quán)重設(shè)置輪詢(xún)比率
- LeastActiveLoadBalance 最少活躍數(shù) 根據(jù)當(dāng)前連接數(shù)來(lái)分配蟹地,越慢的提供者收到越少的請(qǐng)求积暖。
- ConsistenHashLoadaBalance 一致性哈希 相同參數(shù)的請(qǐng)求總是發(fā)到同一提供者,如果一臺(tái)機(jī)器掛了怪与,則平攤分發(fā)到虛擬節(jié)點(diǎn)夺刑,默認(rèn)只對(duì)第一個(gè)參數(shù)做hash,默認(rèn)160個(gè)虛擬節(jié)點(diǎn)
自定義負(fù)載均衡算法——原理:
? 啟動(dòng)時(shí)服務(wù)提供者將當(dāng)前進(jìn)程啟動(dòng)時(shí)間注冊(cè)到ZK分别;服務(wù)消費(fèi)者發(fā)現(xiàn)該節(jié)點(diǎn)后計(jì)算服務(wù)啟動(dòng)時(shí)間(相對(duì)當(dāng)前時(shí)間)遍愿,在默認(rèn)預(yù)熱時(shí)間的前20%時(shí)間內(nèi),該節(jié)點(diǎn)權(quán)重始終固定為2耘斩,這樣客戶(hù)端的負(fù)載均衡器只會(huì)分發(fā)極少的請(qǐng)求至節(jié)點(diǎn)沼填。
? 在預(yù)熱時(shí)間之后的80%時(shí)間內(nèi),該節(jié)點(diǎn)權(quán)重將隨著時(shí)間的推移而線性增長(zhǎng)煌往;待預(yù)熱時(shí)間到期后倾哺,權(quán)重自動(dòng)恢復(fù)為默認(rèn)值100;負(fù)載均衡器的內(nèi)核是一個(gè)標(biāo)準(zhǔn)的WLC算法模塊刽脖,即加權(quán)最少連接算法羞海;
? 如果某個(gè)節(jié)點(diǎn)Hang住或宕機(jī),其權(quán)重會(huì)迅速自動(dòng)調(diào)節(jié)降低曲管,避免持續(xù)性影響却邓;當(dāng)節(jié)點(diǎn)下線時(shí),服務(wù)端提前觸發(fā)權(quán)重調(diào)節(jié)院水,重載默認(rèn)權(quán)重至1并發(fā)布到注冊(cè)中心腊徙,服務(wù)消費(fèi)者將迅速感知到該事件;
服務(wù)提供者優(yōu)雅下線步驟(注意這套邏輯僅在服務(wù)端執(zhí)行)在ok.htm?down=true對(duì)應(yīng)的controller中加入下列邏輯檬某,注意要判斷down是否為true撬腾,因?yàn)檎?lái)說(shuō)false表示啟動(dòng)驗(yàn)證而不是關(guān)機(jī)
- 調(diào)用smartServerHelper.setOverrideWeight(1);將當(dāng)前服務(wù)端的權(quán)重設(shè)置為1恢恼;等待5秒民傻;
- 調(diào)用smartServerHelper.prepareShutdown();將當(dāng)前服務(wù)端置為臨時(shí)禁用(當(dāng)進(jìn)程結(jié)束后該狀態(tài)會(huì)被自動(dòng)清除)
- 等待1秒;
- 正常關(guān)閉進(jìn)程漓踢;
- 在關(guān)機(jī)腳本(一般為shutdown)的stop方法中牵署,調(diào)用/ok.htm?down=true
服務(wù)者消費(fèi)者配置
<dubbo:consumer loadbalance="smart"/>
dubbo服務(wù)支持參數(shù)動(dòng)態(tài)調(diào)整,例如動(dòng)態(tài)調(diào)整權(quán)重喧半,但dubbo實(shí)現(xiàn)方式較為特殊奴迅,并不是常規(guī)思路。
普通狀態(tài)
默認(rèn)情況下挺据,任意一臺(tái)dubbo服務(wù)端上線后會(huì)注冊(cè)到配置中心(zk)取具,路徑為/<group>/<service>/providers節(jié)點(diǎn)名為完整的服務(wù)URI,類(lèi)似下面
dubbo%3A%2F%2F10.57.17.156%3A20880%2Fcn.tongdun.arch.dbench.IDbenchService%3Fanyhost%3Dtrue%26application%3Ddbench%26default.remote.timestamp%3D1553248880792%26dubbo%3D2.8.4%26generic%3Dfalse%26interface%3Dcn.tongdun.arch.dbench.IDbenchService%26methods%3DgetTotalPayloadSize%2CtestWithSleep%26pid%3D798%26revision%3D1.0%26side%3Dprovider%26timestamp%3D1553248881596%26version%3D1.0.1%26warmup%3D600000
這個(gè)節(jié)點(diǎn)本身是具有瞬時(shí)性和不變性吴菠,機(jī)器下線時(shí)將自動(dòng)刪除者填,那dubbo怎么保存動(dòng)態(tài)修改的值呢?
覆蓋狀態(tài)
對(duì)于動(dòng)態(tài)配置做葵,dubbo將在zk的 /<group>/<service>/configurators 路徑下單獨(dú)發(fā)布一條URI占哟,例如調(diào)整某臺(tái)機(jī)器權(quán)重后,會(huì)產(chǎn)生下面的節(jié)點(diǎn)override%3A%2F%2F10.57.17.156%3A20880%2Fcn.tongdun.arch.dbench.IDbenchService%3Fcategory%3Dconfigurators%26dynamic%3Dtrue%26version%3D1.0.1%26weight%3D1
這個(gè)節(jié)點(diǎn)不具備瞬時(shí)性(跟普通狀態(tài)的節(jié)點(diǎn)不一樣)酿矢,也就是說(shuō)這條動(dòng)態(tài)配置一經(jīng)發(fā)布榨乎,不會(huì)自動(dòng)刪除。另外瘫筐,可以任意發(fā)布多條動(dòng)態(tài)配置蜜暑,最終體現(xiàn)在zk里的順序是隨機(jī)的。
客戶(hù)端
客戶(hù)端訂閱服務(wù)后策肝,會(huì)去zk拉取普通狀態(tài)節(jié)點(diǎn)和覆蓋狀態(tài)下的所有節(jié)點(diǎn)肛捍,將所有的狀態(tài)的節(jié)點(diǎn)進(jìn)行疊加后,得到最終的訂閱配置數(shù)據(jù)之众。因此如果發(fā)布了動(dòng)態(tài)配置而不刪除拙毫,則可能會(huì)導(dǎo)致客戶(hù)端得到的配置錯(cuò)亂,造成不可預(yù)料之后果
服務(wù)暴露原理
- 暴露本地服務(wù)
- 暴露遠(yuǎn)程服務(wù)
- 啟動(dòng)netty
- 連接zookeeper
- 到zookeeper注冊(cè)
- 監(jiān)聽(tīng)zookeeper
? ServiceConfig類(lèi)拿到對(duì)外提供服務(wù)的實(shí)際類(lèi)ref棺禾,然后通過(guò)ProxyFactory類(lèi)的getInvoker方法使用ref生成一個(gè)AbstractProxyInvoker實(shí)例缀蹄,到這一步就完成具體服務(wù)到Invoker的轉(zhuǎn)換(javassistProxyFacory、JdkProxyFactory)膘婶,接著要做Invoker轉(zhuǎn)換到Export的過(guò)程
? 服務(wù)發(fā)布:本地暴露缺前、遠(yuǎn)程暴露
? 為什么會(huì)有本地暴露
和遠(yuǎn)程暴露
呢?不從場(chǎng)景考慮討論技術(shù)的沒(méi)有意義是.在dubbo中我們一個(gè)服務(wù)可能既是Provider
,又是Consumer
,因此就存在他自己調(diào)用自己服務(wù)的情況,如果再通過(guò)網(wǎng)絡(luò)去訪問(wèn),那自然是舍近求遠(yuǎn),因此他是有本地暴露
服務(wù)的這個(gè)設(shè)計(jì).從這里我們就知道這個(gè)兩者的區(qū)別
- 本地暴露是暴露在JVM中,不需要網(wǎng)絡(luò)通信. url是inJvm開(kāi)頭
- 遠(yuǎn)程暴露是將ip,端口等信息暴露給遠(yuǎn)程客戶(hù)端,調(diào)用時(shí)需要網(wǎng)絡(luò)通信.url是registry開(kāi)頭
本地暴露:
遠(yuǎn)程暴露
ServiceConfig ------> ref
↓
ProxyFactory --------> Javassist、JDK動(dòng)態(tài)代理
↓
Invoker ----------> AbstractProxyInvoker
↓
Protocol --------> Dubbo悬襟、injvm等
↓
Exporter
1衅码、spring啟動(dòng),解析配置文件
2脊岳、創(chuàng)建dubbo標(biāo)簽解析器
3逝段、解析dubbo標(biāo)簽
4筛璧、ServiceBean解析
5、容器創(chuàng)建完成惹恃,觸發(fā)ContextRefrestEvent
6、export暴露服務(wù)
7棺牧、duExportUrls
8巫糙、doExportUrlsFor1Protocol
- JavassistProxyFactory模式原理:創(chuàng)建Wrapper子類(lèi),在子類(lèi)中實(shí)現(xiàn)invokeMethod方法颊乘,方法體內(nèi)會(huì)為每個(gè)ref方法都做方法名和方法參數(shù)匹配校驗(yàn)参淹,如果匹配則直接調(diào)用即可,相比JDKProxyFactory省去了反射調(diào)用的開(kāi)銷(xiāo)乏悄。
- JDKProxyFactory:通過(guò)反射獲取真實(shí)對(duì)象的方法浙值,然后調(diào)用即可。
9檩小、getInvoker
10开呐、protocol.export
11、開(kāi)啟服務(wù)器 openServer()如nettyServer
12规求、注冊(cè)服務(wù)到注冊(cè)中心 registerProvider
getRegistry() 方法根據(jù)注冊(cè)中心類(lèi)型(默認(rèn) Zookeeper)獲取注冊(cè)中心客戶(hù)端筐付,由注冊(cè)中心客戶(hù)端實(shí)例來(lái)進(jìn)行真正的服務(wù)注冊(cè)。注冊(cè)中心客戶(hù)端將節(jié)點(diǎn)注冊(cè)到注冊(cè)中心阻肿,同時(shí)訂閱對(duì)應(yīng)的 override 數(shù)據(jù)瓦戚,實(shí)時(shí)監(jiān)聽(tīng)服務(wù)的屬性變動(dòng)實(shí)現(xiàn)動(dòng)態(tài)配置功能。最終返回的 Exporter 實(shí)現(xiàn)了 unexport() 方法丛塌,這樣在服務(wù)下線時(shí)清理相關(guān)資源较解。
- 委托具體協(xié)議(Dubbo)進(jìn)行服務(wù)暴露,創(chuàng)建NettyServer監(jiān)聽(tīng)端口和保存服務(wù)實(shí)例赴邻。
- 創(chuàng)建注冊(cè)中心對(duì)象印衔,與注冊(cè)中心創(chuàng)建TCP連接。
- 注冊(cè)服務(wù)元數(shù)據(jù)到注冊(cè)中心乍楚。
- 訂閱configuators節(jié)點(diǎn)当编,監(jiān)聽(tīng)服務(wù)動(dòng)態(tài)屬性變更事件。
- 服務(wù)銷(xiāo)毀收尾工作徒溪,比如關(guān)閉端口忿偷、反注冊(cè)服務(wù)信息等。
Filter 在服務(wù)暴露前臊泌,做攔截器初始化鲤桥,在加載所有攔截器時(shí)會(huì)過(guò)濾支隊(duì)provider生效的數(shù)據(jù)。
ZK連接
dubbo中zookeeper做注冊(cè)中心,如果注冊(cè)中心集群都掛掉,那發(fā)布者和訂閱者還能通信嗎?
可以渠概。zookeeper的信息會(huì)緩存到本地作為一個(gè)緩存文件,并且轉(zhuǎn)換成properties
對(duì)象方便使用茶凳。建立線程池嫂拴,定時(shí)檢測(cè)并連接注冊(cè)中心,失敗了就重連贮喧。
創(chuàng)建節(jié)點(diǎn)
注冊(cè)服務(wù)到zk其實(shí)就是在zk上創(chuàng)建臨時(shí)節(jié)點(diǎn)筒狠,當(dāng)節(jié)點(diǎn)下線或者down掉時(shí),即會(huì)刪除臨時(shí)節(jié)點(diǎn)箱沦,從而使服務(wù)從可用列表中剔除辩恼。
持久節(jié)點(diǎn)
所謂持久節(jié)點(diǎn),是指在節(jié)點(diǎn)創(chuàng)建后,就一直存在,直到有刪除操作來(lái)主動(dòng)清除這個(gè)節(jié)點(diǎn),也就是說(shuō)不會(huì)因?yàn)閯?chuàng)建該節(jié)點(diǎn)的客戶(hù)端會(huì)話失效而消失
臨時(shí)節(jié)點(diǎn)
臨時(shí)節(jié)點(diǎn)的生命周期和客戶(hù)端會(huì)話綁定,也就是說(shuō),如果客戶(hù)端會(huì)話失效,那么這個(gè)節(jié)點(diǎn)就會(huì)自動(dòng)被清除掉
1、export的時(shí)候進(jìn)行zk訂閱
2谓形、設(shè)置監(jiān)聽(tīng)回調(diào)的地址灶伊,回調(diào)給FailbackRegistry的notify
3、創(chuàng)建持久節(jié)點(diǎn)
4寒跳、設(shè)置對(duì)該節(jié)點(diǎn)的監(jiān)聽(tīng)
5聘萨、更新新的服務(wù)信息,服務(wù)啟動(dòng)和節(jié)點(diǎn)更新回調(diào)童太,都會(huì)調(diào)用到這里
6米辐、更新緩存文件
7、對(duì)比新舊信息是否有變化康愤,有則重新暴露服務(wù)
服務(wù)暴露總結(jié):
服務(wù)降級(jí)
為什么需要服務(wù)降級(jí)
高并發(fā)大業(yè)務(wù)量情況下儡循,暫時(shí)屏蔽邊緣業(yè)務(wù)
怎么做?
MockClusterInvoker
- no mock 直接調(diào)用
- force:direct mock 直接不調(diào)用征冷,返回一個(gè)之前設(shè)置的值
- fail-mock 調(diào)用失敗后择膝,返回一個(gè)設(shè)置的值
服務(wù)引用
Dubbo 服務(wù)引用的時(shí)機(jī)有兩個(gè),第一個(gè)是在 Spring 容器調(diào)用 ReferenceBean 的 afterPropertiesSet 方法時(shí)引用服務(wù)检激,第二個(gè)是在 ReferenceBean 對(duì)應(yīng)的服務(wù)被注入到其他類(lèi)中時(shí)引用肴捉。這兩個(gè)引用服務(wù)的時(shí)機(jī)區(qū)別在于,第一個(gè)是餓漢式的叔收,第二個(gè)是懶漢式的齿穗。默認(rèn)情況下,Dubbo 使用懶漢式引用服務(wù)饺律。如果需要使用餓漢式窃页,可通過(guò)配置 <dubbo:reference> 的 init 屬性開(kāi)啟。下面我們按照 Dubbo 默認(rèn)配置進(jìn)行分析复濒,整個(gè)分析過(guò)程從 ReferenceBean 的 getObject 方法開(kāi)始脖卖。當(dāng)我們的服務(wù)被注入到其他類(lèi)中時(shí),Spring 會(huì)第一時(shí)間調(diào)用 getObject 方法巧颈,并由該方法執(zhí)行服務(wù)引用邏輯畦木。按照慣例,在進(jìn)行具體工作之前砸泛,需先進(jìn)行配置檢查與收集工作十籍。接著根據(jù)收集到的信息決定服務(wù)用的方式蛆封,有三種,第一種是引用本地 (JVM) 服務(wù)勾栗,第二是通過(guò)直連方式引用遠(yuǎn)程服務(wù)惨篱,第三是通過(guò)注冊(cè)中心引用遠(yuǎn)程服務(wù)。不管是哪種引用方式围俘,最后都會(huì)得到一個(gè) Invoker 實(shí)例妒蛇。如果有多個(gè)注冊(cè)中心,多個(gè)服務(wù)提供者楷拳,這個(gè)時(shí)候會(huì)得到一組 Invoker 實(shí)例,此時(shí)需要通過(guò)集群管理類(lèi) Cluster 將多個(gè) Invoker 合并成一個(gè)實(shí)例吏奸。合并后的 Invoker 實(shí)例已經(jīng)具備調(diào)用本地或遠(yuǎn)程服務(wù)的能力了欢揖,但并不能將此實(shí)例暴露給用戶(hù)使用,這會(huì)對(duì)用戶(hù)業(yè)務(wù)代碼造成侵入奋蔚。此時(shí)框架還需要通過(guò)代理工廠類(lèi) (ProxyFactory) 為服務(wù)接口生成代理類(lèi)她混,并讓代理類(lèi)去調(diào)用 Invoker 邏輯。避免了 Dubbo 框架代碼對(duì)業(yè)務(wù)代碼的侵入泊碑,同時(shí)也讓框架更容易使用坤按。
- 將spring的schemas標(biāo)簽信息轉(zhuǎn)換ReferenceBean,然后通過(guò)這個(gè)bean的信息,連接、訂閱zookeeper節(jié)點(diǎn)信息創(chuàng)建一個(gè)
invoker
- 將
invoker
的信息創(chuàng)建一個(gè)動(dòng)態(tài)代理對(duì)象(createProxy) - 1馒过、加載配置中心拼裝成urls
- 2臭脓、遍歷urls調(diào)用refProtocol創(chuàng)建遠(yuǎn)程的動(dòng)態(tài)代理Invoker
- 3、調(diào)用proxyFacotry創(chuàng)建服務(wù)代理(javassistProxyFacotry)
SPI
? SPI 全稱(chēng)為 Service Provider Interface腹忽,是一種服務(wù)發(fā)現(xiàn)機(jī)制来累。SPI 的本質(zhì)是將接口實(shí)現(xiàn)類(lèi)的全限定名配置在文件中,并由服務(wù)加載器讀取配置文件窘奏,加載實(shí)現(xiàn)類(lèi)嘹锁。這樣可以在運(yùn)行時(shí),動(dòng)態(tài)為接口替換實(shí)現(xiàn)類(lèi)着裹。正因此特性领猾,我們可以很容易的通過(guò) SPI 機(jī)制為我們的程序提供拓展功能。SPI 機(jī)制在第三方框架中也有所應(yīng)用骇扇,比如 Dubbo 就是通過(guò) SPI 機(jī)制加載所有的組件摔竿。不過(guò),Dubbo 并未使用 Java 原生的 SPI 機(jī)制匠题,而是對(duì)其進(jìn)行了增強(qiáng)拯坟,使其能夠更好的滿(mǎn)足需求。在 Dubbo 中韭山,SPI 是一個(gè)非常重要的模塊郁季±淅#基于 SPI,我們可以很容易的對(duì) Dubbo 進(jìn)行拓展梦裂。如果大家想要學(xué)習(xí) Dubbo 的源碼似枕,SPI 機(jī)制務(wù)必弄懂。接下來(lái)年柠,我們先來(lái)了解一下 Java SPI 與 Dubbo SPI 的用法凿歼,然后再來(lái)分析 Dubbo SPI 的源碼。