Java/Spring/Dubbo三種SPI機(jī)制看幼,到底誰更好批旺?

SPI 機(jī)制應(yīng)用在了大家項(xiàng)目中的很多地方,在很多框架中也有普遍應(yīng)用诵姜,只不過很多人并沒有感知汽煮。

舉個(gè)例子,為什么我們?cè)陧?xiàng)目中引入 mysql-connector 的 jar 包棚唆,就可以直接連接 MySQL 數(shù)據(jù)庫(kù)了暇赤?

本篇文章就來介紹一下 SPI,聊聊 Java 宵凌、Spring鞋囊、Dubbo 中的 SPI 機(jī)制。

SPI

SPI ( Service Provider Interface)瞎惫,是一種服務(wù)發(fā)現(xiàn)機(jī)制溜腐。

SPI 的本質(zhì)是將接口的實(shí)現(xiàn)類的全限定名配置在文件中,并由服務(wù)加載器讀取配置文件瓜喇,加載對(duì)應(yīng)接口的實(shí)現(xiàn)類挺益。這樣就可以在運(yùn)行時(shí),獲取接口的實(shí)現(xiàn)類乘寒。

通過這一特性望众,我們可以很容易地通過 SPI 機(jī)制為程序提供拓展功能。

Java SPI

Java SPI 機(jī)制:

Java SPI 是“基于接口的編程+策略模式+配置文件”組合實(shí)現(xiàn)的動(dòng)態(tài)加載機(jī)制。

設(shè)計(jì)一個(gè)接口烂翰,將接口的實(shí)現(xiàn)類寫在配置文件中叉袍,服務(wù)通過讀取配置文件來發(fā)現(xiàn)實(shí)現(xiàn)類,進(jìn)行加載實(shí)例化然后使用刽酱。

配置文件路徑:classpath下的META-INF/services/

配置文件名:接口的全限定名

配置文件內(nèi)容:接口的實(shí)現(xiàn)類的權(quán)限定名

應(yīng)用舉例:

1喳逛、自定義接口

// 接口
public interface Superman {
void introduce();
}

// 實(shí)現(xiàn)類1
public class IronMan implements Superman{
@Override
public void introduce() {
System.out.println("我是鋼鐵俠!");
}
}
// 實(shí)現(xiàn)類2
public class CaptainAmerica implements Superman {
@Override
public void introduce() {
System.out.println("我是美國(guó)隊(duì)長(zhǎng)棵里!");
}
}

配置文件:

測(cè)試:

public static void main(String[] args) {
ServiceLoader<Superman> serviceLoader = ServiceLoader.load(Superman.class);
System.out.println("Java SPI:");
serviceLoader.forEach(Superman::introduce);
}

運(yùn)行結(jié)果:

2润文、java.sql.Driver 接口

MySQL 的實(shí)現(xiàn):

看到這里,你應(yīng)該就知道開頭問題的答案了殿怜,mysql-connector 的 jar 表中正是通過 SPI 的方式實(shí)現(xiàn)了 java 的 Driver 接口典蝌,所以我們的服務(wù)可以在運(yùn)行時(shí)獲取到 mysql 的驅(qū)動(dòng)類,從而連接 mysql 头谜。

Java SPI 原理:

Java SPI 地實(shí)現(xiàn)在 ServiceLoader 類:

這里截取部分代碼骏掀,有興趣的同學(xué)自行閱讀。

獲取prefix下的配置文件(包括 jar 包):

Java SPI 總結(jié):

Java SPI 機(jī)制:為某個(gè)接口發(fā)現(xiàn)/尋找服務(wù)實(shí)現(xiàn)的機(jī)制柱告。

優(yōu)點(diǎn):

核心思想:解耦截驮,使得第三方服務(wù)模塊的裝配控制的邏輯與調(diào)用者的業(yè)務(wù)代碼分離〖识龋可以根據(jù)實(shí)際業(yè)務(wù)情況進(jìn)行使用或擴(kuò)展葵袭。

缺點(diǎn):

1、獲取接口的實(shí)現(xiàn)類的方式不靈活
serviceLoader 只能通過 Iterator 形式遍歷獲取乖菱,不能根據(jù)參數(shù)獲取指定的某個(gè)實(shí)現(xiàn)類坡锡。

2、資源浪費(fèi)

serviceLoader 只能通過遍歷的方式將接口的實(shí)現(xiàn)類全部獲取窒所、加載并實(shí)例化一遍鹉勒。如果不想用某些實(shí)現(xiàn)類,它也會(huì)被加載并實(shí)例化吵取,造成浪費(fèi)禽额。

Spring SPI

與 JDK SPI 類似, 相對(duì)于 Java 的 SPI 的優(yōu)勢(shì)在于:

Spring SPI 指定配置文件為 classpath 下的 META-INF/spring.factories海渊,所有的拓展點(diǎn)配置放到一個(gè)文件中绵疲。

配置文件內(nèi)容為 key-value 類型,key 為接口的全限定名臣疑, value 為實(shí)現(xiàn)類的全限定名盔憨,可以為多個(gè)。

spring.factories 文件舉例:

應(yīng)用舉例:

以 dubbo 的使用舉例:

為什么我們?cè)陧?xiàng)目中引入 dubbo jar 包讯沈,application.yml 中配置 registry郁岩,provider 等婿奔,就可以直接通過使用 dubbo 的 Service 注解和 Reference 注解來使用 dubbo 服務(wù)了?

哪有什么歲月靜好问慎,不過是有人替你負(fù)重前行萍摊。“負(fù)重前行的人”就是 "dubbo-spring-boot-starter" 如叼。其實(shí)就是用到了 spring SPI :

以 EnableAutoConfiguration 的實(shí)現(xiàn)類 DubboAutoConfiguration 為例:

在 spring boot 啟動(dòng)過程中 冰木,在 SpringFactoriesLoader.loadFactoryNames(type, classLoader) 這一步中會(huì)將 EnableAutoConfiguration 的實(shí)現(xiàn)類全部進(jìn)行加載、解析笼恰、初始化踊沸。

在實(shí)例化 EnableAutoConfiguration 的實(shí)現(xiàn)類時(shí),會(huì)執(zhí)行實(shí)現(xiàn)類 dubboAutoConfiguration 中的具體邏輯社证,將 dubbo 服務(wù)器啟動(dòng)并注冊(cè)到 spring 容器中逼龟。

DubboAutoConfiguration的大概實(shí)現(xiàn):

讀取配置文件中的配置項(xiàng)值(配置項(xiàng):DubboConfigConfiguration)生成多個(gè)配置 bean,掃描 dubbo @Service 和 @Reference 注解的類追葡,生成對(duì)應(yīng)的 bean腺律。

其實(shí)在我們使用的第三方依賴包中,很多都使用了 Spring SPI宜肉,如 dubbo匀钧,mybatis,redisson 等等崖飘。

Dubbo SPI

dubbo的 Filter榴捡、Protocol杈女、Cluster朱浴、LoadBalance 等都是通過 SPI 的方式進(jìn)行拓展加載的。

特點(diǎn):

1达椰、dubbo SPI 為每個(gè)拓展點(diǎn)(接口)單獨(dú)設(shè)置一個(gè)文件翰蠢,文件名為接口的全限定名。如org.apache.dubbo.rpc.Filter啰劲,org.apache.dubbo.rpc.Protocol梁沧,org.apache.dubbo.rpc.cluster.LoadBalance 等。

dubbo SPI 配置文件舉例:

2蝇裤、支持"別名的概念“廷支,可以通過別名獲取拓展點(diǎn)的某個(gè)實(shí)現(xiàn)。

配置文件內(nèi)容是 key -value 類型栓辜,key 是別名恋拍,value 是實(shí)現(xiàn)類的全限定名。

只使用指定的 filter 藕甩,就不會(huì)實(shí)例化其他 filter 施敢。

3、支持 Dubbo 內(nèi)部的依賴注入

Dubbo IOC

通過 setter 方法進(jìn)行依賴注入。Dubbo 首先會(huì)通過反射獲取到實(shí)例的所有方法僵娃,然后再遍歷方法列表概作,檢測(cè)方法名是否具有 setter 方法特征。若有默怨,則通過 ObjectFactory 獲取依賴對(duì)象讯榕,最后通過反射調(diào)用 setter 方法將依賴設(shè)置到目標(biāo)對(duì)象中。

實(shí)現(xiàn):

dubbo SPI 的實(shí)現(xiàn)在 ExtensionLoader 這個(gè)類匙睹。

以獲取所有的 dubbo Filter 為例:

1瘩扼、首先獲取 Filter 的 ExtensionLoader

ExtensionLoader.getExtensionLoader(Filter.class)

2、由 ExtensionLoader 從配置文件中加載所有的拓展類

加載項(xiàng)目中及 jar 包下以下目錄的配置文件:

配置文件名為接口的全限定名垃僚。

3集绰、讀取配置文件時(shí),根據(jù) ’=‘ 為界限谆棺,確認(rèn)鍵值對(duì)栽燕。

由此得到“配置項(xiàng)名稱”到“配置類”的映射關(guān)系表

4、過程中多處使用緩存提升性能改淑。

緩存拓展類對(duì)應(yīng)的 ExtensionLoader 等碍岔。

獲取到 別名 – 實(shí)現(xiàn)類的全限定名后,即可直接通過別名去獲取指定的拓展類朵夏。

Java蔼啦、Spring、Dubbo SPI 對(duì)比

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末仰猖,一起剝皮案震驚了整個(gè)濱河市捏肢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌饥侵,老刑警劉巖鸵赫,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異躏升,居然都是意外死亡辩棒,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門膨疏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來一睁,“玉大人,你說我怎么就攤上這事佃却≌哂酰” “怎么了?”我有些...
    開封第一講書人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵双霍,是天一觀的道長(zhǎng)砚偶。 經(jīng)常有香客問我批销,道長(zhǎng),這世上最難降的妖魔是什么染坯? 我笑而不...
    開封第一講書人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任均芽,我火速辦了婚禮,結(jié)果婚禮上单鹿,老公的妹妹穿的比我還像新娘掀宋。我一直安慰自己,他們只是感情好仲锄,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開白布劲妙。 她就那樣靜靜地躺著,像睡著了一般儒喊。 火紅的嫁衣襯著肌膚如雪镣奋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,578評(píng)論 1 305
  • 那天怀愧,我揣著相機(jī)與錄音侨颈,去河邊找鬼。 笑死芯义,一個(gè)胖子當(dāng)著我的面吹牛哈垢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播扛拨,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼耘分,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了绑警?” 一聲冷哼從身側(cè)響起求泰,我...
    開封第一講書人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎待秃,沒想到半個(gè)月后拜秧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡章郁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了志衍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片暖庄。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖楼肪,靈堂內(nèi)的尸體忽然破棺而出培廓,到底是詐尸還是另有隱情,我是刑警寧澤春叫,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布肩钠,位于F島的核電站泣港,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏价匠。R本人自食惡果不足惜当纱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望踩窖。 院中可真熱鬧坡氯,春花似錦、人聲如沸洋腮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽啥供。三九已至悯恍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間伙狐,已是汗流浹背坪稽。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鳞骤,地道東北人窒百。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像豫尽,于是被迫代替她去往敵國(guó)和親篙梢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容