1. 問題的由來
條條大路通羅馬芭逝,實(shí)現(xiàn)相同的功能可以使用不同的方案氏身,比如說dubbo代理生成的方案,有人喜歡用JDK動態(tài)代理含滴,有人喜歡用javasist生成字節(jié)碼的方式來生成代理痰哨。RPC協(xié)議可以使用dubbo協(xié)議胶果,也可以使用RMI協(xié)議。那么問題來了斤斧,既然實(shí)現(xiàn)同樣的功能有多種方案早抠,而dubbo又不能強(qiáng)行用戶必須要使用哪一種方案,總不能寫死在代碼里吧撬讽,那么如何做到在運(yùn)行時根據(jù)我的需要自由切換呢蕊连?
2. 解決過程
dubbo想達(dá)到的效果就是根據(jù)用戶傳入的參數(shù)來自動找到合適的方案。
2.1 我能想到最簡單的方法就是:
if(參數(shù)==“dubbo”){
return new DubboProtocol();
}else if(參數(shù) == "rmi"){
return new RMIProtocol();
}
...... .......
這樣也可以解決問題啊游昼,用戶參數(shù)里指定啥協(xié)議甘苍,我返回給你啥協(xié)議
2.2 能不寫if else嗎?
萬一哪天又出了一種牛逼的rpc協(xié)議叫做NBProtocol烘豌,難道要去改代碼多加個if else嗎载庭?
那好吧,那我使用設(shè)計模式之 -- 策略模式廊佩,不就解決了囚聚?對外暴露的接口都是一樣的,只是內(nèi)部的一小部分算法我可以自由替換标锄,也就是說顽铸,啟動的時候把所有協(xié)議統(tǒng)統(tǒng)掃描進(jìn)來,最終的效果就是策略模式內(nèi)部維護(hù)一個這樣的map:
name | className |
---|---|
dubbo | com.xxx.xxx.DubboProtocol |
rmi | com.xxx.xxx.RMIProtocol |
nb | com.xxx.xxx.NBProtocol |
如果用戶外邊傳一個參數(shù)叫“rmi”料皇,我就map.get("rmi"),這樣就得到了RMIProtocol谓松。
2.3 鳥不拉屎的位置
感覺好像已經(jīng)解決了,但是好像有點(diǎn)不對践剂,上面說啟動的時候把所有協(xié)議統(tǒng)統(tǒng)掃描進(jìn)來毒返,咋掃描?去哪掃描舷手?你的這個牛逼的NBProtocol協(xié)議有可能是在哪個旮旯的jar里拧簸,也有可能是在哪個鳥不拉屎的package下面,也有可能在文件系統(tǒng)里男窟,也有可能在遙遠(yuǎn)的網(wǎng)絡(luò)上盆赤,你讓dubbo去哪找你哪個牛逼的NBProtocol?
那這也好辦歉眷,我dubbo就規(guī)定了牺六,你自己寫的擴(kuò)展的協(xié)議都要放在xxx.xxxx這個classpath下,不放不加載汗捡,到時候找不到可別怪我沒跟你說過淑际。恩畏纲,就這樣,按照事先約定好的約定春缕,就可以解決加載位置的問題盗胀。
2.4 尋找優(yōu)越感
按理說已經(jīng)解決了之前說動態(tài)加載的問題了,但是呢锄贼,作為一個牛逼的框架票灰,總得寫點(diǎn)別人看不懂的代碼吧,不然優(yōu)越感哪里來宅荤?
好吧屑迂,之前java 1.6 就引入了一種叫做spi的東西,主要就是為了做到服務(wù)發(fā)現(xiàn)和動態(tài)擴(kuò)展冯键,SPI英文為Service Provider Interface惹盼。 但是呢,如果直接就用spi雖然也勉強(qiáng)可以惫确,但不改點(diǎn)東西豈不是太low了逻锐,我dubbo的優(yōu)越感哪里找?雕薪?何況原生的spi確實(shí)有點(diǎn)小問題昧诱,那就是他一上來就把你要的類全都實(shí)例化了(我只是多放幾個在哪里裝裝逼,壓根沒想去用所袁,別那么較真)盏档。于是乎dubbo就搞出來一個,而且是按需實(shí)例化燥爷。人家java spi里有serviceloader蜈亩,dubbo就來個extensionloader,意思都一樣前翎,都是負(fù)責(zé)去加載自定義的擴(kuò)展點(diǎn)的稚配。人家java spi 規(guī)定了自己 寫的擴(kuò)展點(diǎn)必須要在 /META-INF/services/ 下邊有一個文件(文件名是接口完全限定名,內(nèi)容是接口實(shí)現(xiàn)類)港华,dubbo也來個規(guī)定道川,必須在
這3個文件夾(任意一個)下有一些特殊文件(文件名為接口名,內(nèi)容是key=value形式的擴(kuò)展點(diǎn)配置)立宜,總言而之冒萄,原理是和java spi的原理一毛一樣 。
3. 最后讓我們來舉個栗子橙数,使用咱自定義的NBProtocol來暴露服務(wù)尊流。#####
-
弄一個jar包,jar結(jié)構(gòu)如下
Paste_Image.png 新建一個dubbo provider的工程灯帮,pom里依賴上面的jar崖技,里面的spring xml 配置加上這個
3.首先在一開始加載的時候會掃描到我們自定義的協(xié)議逻住,
在往下走,運(yùn)行到了斷點(diǎn)這個位置迎献,說明開始暴露服務(wù)了瞎访,說明咱的牛逼協(xié)議流程可以通了
總結(jié)
上面就是我的一些關(guān)于擴(kuò)展點(diǎn)加載機(jī)制的了解,最直觀的感受是忿晕,有了擴(kuò)展點(diǎn)明顯感覺生活質(zhì)量明顯提高了不少装诡,因?yàn)椴还芎锬犟R月银受,不管你是蹲在那個陰暗的角落践盼,只要按照規(guī)范弄個jar包丟到classpath中,你可以直接替換原來的功能了宾巍,讓我們看下dubbo自帶哪些擴(kuò)展點(diǎn)
哇咕幻!這幫人真能寫啊,也就是說這些東東我們統(tǒng)統(tǒng)能換掉顶霞,學(xué)習(xí)了上面的知識肄程,讓我們分分鐘把dubbo改的面目全非吧!选浑!