Java api和spi那點(diǎn)事

api

API(Application Programming Interface ): 在java中,我們使用java提供的很多類、類的方法、數(shù)據(jù)結(jié)構(gòu)來(lái)編寫(xiě)我們的應(yīng)用程序,最終完成我們需求的程序功能,這里的類、方法、數(shù)據(jù)結(jié)構(gòu)即是jdk提供的api。api的意義,其實(shí)就是這些提供給你完成某項(xiàng)功能的類、接口或者方法。
API直接為你提供了功能,直接被應(yīng)用開(kāi)發(fā)人員使用

spi

SPI 即 Service Provider Interface ,字面意思就是:“服務(wù)提供者的接口”,我的理解是:專門(mén)提供給服務(wù)提供者或者擴(kuò)展框架功能的開(kāi)發(fā)者去使用的一個(gè)接口。

SPI 將服務(wù)接口和具體的服務(wù)實(shí)現(xiàn)分離開(kāi)來(lái),將服務(wù)調(diào)用方和服務(wù)實(shí)現(xiàn)者解耦,能夠提升程序的擴(kuò)展性、可維護(hù)性。修改或者替換服務(wù)實(shí)現(xiàn)并不需要修改調(diào)用方。

很多框架都使用了 Java 的 SPI 機(jī)制,比如:Spring 框架、數(shù)據(jù)庫(kù)加載驅(qū)動(dòng)、日志接口、以及 Dubbo 的擴(kuò)展實(shí)現(xiàn)等等。

SPI 和 API 有什么區(qū)別?

那 SPI 和 API 有啥區(qū)別?

說(shuō)到 SPI 就不得不說(shuō)一下 API 了,從廣義上來(lái)說(shuō)它們都屬于接口,而且很容易混淆。下面先用一張圖說(shuō)明一下:

API&SPI

一般模塊之間都是通過(guò)接口進(jìn)行通訊,那我們?cè)诜?wù)調(diào)用方和服務(wù)實(shí)現(xiàn)方(也稱服務(wù)提供者)之間引入一個(gè)“接口”。

當(dāng)實(shí)現(xiàn)方提供了接口和實(shí)現(xiàn),我們可以通過(guò)調(diào)用實(shí)現(xiàn)方的接口從而擁有實(shí)現(xiàn)方給我們提供的能力,這就是 API ,這種接口和實(shí)現(xiàn)都是放在實(shí)現(xiàn)方的。

當(dāng)接口存在于調(diào)用方這邊時(shí),就是 SPI ,由接口調(diào)用方確定接口規(guī)則,然后由不同的廠商去根絕這個(gè)規(guī)則對(duì)這個(gè)接口進(jìn)行實(shí)現(xiàn),從而提供服務(wù)。

舉個(gè)通俗易懂的例子:公司 H 是一家科技公司,新設(shè)計(jì)了一款芯片,然后現(xiàn)在需要量產(chǎn)了,而市面上有好幾家芯片制造業(yè)公司,這個(gè)時(shí)候,只要 H 公司指定好了這芯片生產(chǎn)的標(biāo)準(zhǔn)(定義好了接口標(biāo)準(zhǔn)),那么這些合作的芯片公司(服務(wù)提供者)就按照標(biāo)準(zhǔn)交付自家特色的芯片(提供不同方案的實(shí)現(xiàn),但是給出來(lái)的結(jié)果是一樣的)。

SPI 的優(yōu)缺點(diǎn)?

通過(guò) SPI 機(jī)制能夠大大地提高接口設(shè)計(jì)的靈活性,但是 SPI 機(jī)制也存在一些缺點(diǎn),比如:

  • 需要遍歷加載所有的實(shí)現(xiàn)類,不能做到按需加載,這樣效率還是相對(duì)較低的。

  • 當(dāng)多個(gè) ServiceLoader 同時(shí) load 時(shí),會(huì)有并發(fā)問(wèn)題。

Dubbo 的 SPI 機(jī)制

SPI(Service Provider Interface) 機(jī)制被大量用在開(kāi)源項(xiàng)目中,它可以幫助我們動(dòng)態(tài)尋找服務(wù)/功能(比如負(fù)載均衡策略)的實(shí)現(xiàn)。

SPI 的具體原理是這樣的:我們將接口的實(shí)現(xiàn)類放在配置文件中,我們?cè)诔绦蜻\(yùn)行過(guò)程中讀取配置文件,通過(guò)反射加載實(shí)現(xiàn)類。這樣,我們可以在運(yùn)行的時(shí)候,動(dòng)態(tài)替換接口的實(shí)現(xiàn)類。和 IoC 的解耦思想是類似的。

Java 本身就提供了 SPI 機(jī)制的實(shí)現(xiàn)。不過(guò),Dubbo 沒(méi)有直接用,而是對(duì) Java原生的 SPI機(jī)制進(jìn)行了增強(qiáng),以便更好滿足自己的需求。

Dubbo 中的默認(rèn)實(shí)現(xiàn)擴(kuò)展

比如說(shuō)我們想要實(shí)現(xiàn)自己的負(fù)載均衡策略,我們創(chuàng)建對(duì)應(yīng)的實(shí)現(xiàn)類 XxxLoadBalance 實(shí)現(xiàn) LoadBalance 接口或者 AbstractLoadBalance 類。

package com.xxx;
 
import org.apache.dubbo.rpc.cluster.LoadBalance;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.RpcException; 

public class XxxLoadBalance implements LoadBalance {
    public <T> Invoker<T> select(List<Invoker<T>> invokers, Invocation invocation) throws RpcException {
        // ...
    }
}

我們將這個(gè)實(shí)現(xiàn)類的路徑寫(xiě)入到resources 目錄下的 META-INF/dubbo/org.apache.dubbo.rpc.cluster.LoadBalance文件中即可。

src
 |-main
    |-java
        |-com
            |-xxx
                |-XxxLoadBalance.java (實(shí)現(xiàn)LoadBalance接口)
    |-resources
        |-META-INF
            |-dubbo
                |-org.apache.dubbo.rpc.cluster.LoadBalance (純文本文件,內(nèi)容為:xxx=com.xxx.XxxLoadBalance)

其他還有很多可供擴(kuò)展的選擇,可以在官方文檔@SPI擴(kuò)展實(shí)現(xiàn)open in new window這里找到。

Dubbo SPI擴(kuò)展

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容