作為一個(gè)Java工程師,你應(yīng)該要知道SPI機(jī)制

什么是 SPI

SPI是Service Provider Interface的簡(jiǎn)稱,是JDK默認(rèn)提供的一種將接口和實(shí)現(xiàn)類進(jìn)行分離的機(jī)制。這種機(jī)制能將接口和實(shí)現(xiàn)進(jìn)行解耦,大大提升系統(tǒng)的可擴(kuò)展性。

專注于為中小企業(yè)提供做網(wǎng)站、成都做網(wǎng)站服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)惠濟(jì)免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了1000多家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過(guò)網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。

SPI機(jī)制約定:當(dāng)一個(gè)Jar包需要提供一個(gè)接口的實(shí)現(xiàn)類時(shí),這個(gè)Jar包需要在META-INF/services/目錄里同時(shí)創(chuàng)建一個(gè)以服務(wù)接口命名的文件。該文件里就是實(shí)現(xiàn)該服務(wù)接口的具體實(shí)現(xiàn)類。而當(dāng)外部程序裝配這個(gè)模塊的時(shí)候,就能通過(guò)該Jar包META-INF/services/里的配置文件找到具體的實(shí)現(xiàn)類名,并裝載實(shí)例化,完成模塊的注入。

比如下面的列子, jcl-over-slf4j這個(gè)Jar包提供了conmon-logging中 LogFactory這個(gè)接口的實(shí)現(xiàn)。

作為一個(gè)Java工程師,你應(yīng)該要知道SPI機(jī)制
image

文件中的內(nèi)容如下:

作為一個(gè)Java工程師,你應(yīng)該要知道SPI機(jī)制

JDK為了方便查找 服務(wù)的實(shí)現(xiàn),還提供了一個(gè)工具類:java.util.ServiceLoader。

作為一個(gè)Java工程師,你應(yīng)該要知道SPI機(jī)制

上面代碼中使用 ServiceLoader遍歷使用SPI機(jī)制提供的所有 LogFactory實(shí)現(xiàn)。

應(yīng)用場(chǎng)景

SPI機(jī)制的主要應(yīng)用有框架擴(kuò)展和組件的替換等,比如

  • JDBC接口實(shí)現(xiàn)類的運(yùn)行時(shí)加載:我們連接具體的數(shù)據(jù)庫(kù)是都需要添加相關(guān)的Jar包依賴,但是不需要我們?cè)僮鋈魏纹渌渲?,只要將Jar包放到classpath下就行了。這是一個(gè)最常見(jiàn)的SPI應(yīng)用場(chǎng)景。
  • 日志門面加載具體的日志實(shí)現(xiàn)類:之前的博客中介紹到,jcl和slf4j等只是日志實(shí)現(xiàn)類,Log4j和LOgBack才是具體的日志實(shí)現(xiàn)。JCL和SLF4J加載日志實(shí)現(xiàn)類時(shí)也使用了SPI機(jī)制,具體請(qǐng)看上面章節(jié)中舉的列子。
  • Spring中大量使用了SPI:比如對(duì)servlet3.0規(guī)范對(duì)ServletContainerInitializer的實(shí)現(xiàn)、自動(dòng)類型轉(zhuǎn)換Type Conversion SPI(Converter SPI、Formatter SPI)等

自己實(shí)現(xiàn)

下面就一步步從定義接口到提供SPI實(shí)現(xiàn)類來(lái)演示下SPI機(jī)制具體的使用方式。

step1:先定義一個(gè)接口

<pre class="java" style="margin: 10px 0px; padding: 0px; white-space: pre !important; word-wrap: break-word; position: relative !important;">

Copy

`public interface SaySomething {

String say(String name);

}`</pre>

step2:編寫實(shí)現(xiàn)類

<pre class="java" style="margin: 10px 0px; padding: 0px; white-space: pre !important; word-wrap: break-word; position: relative !important;">

Copy

public class ASaySomething implements SaySomething { @Override public String say(String name) { return "Hi,"+name+", l am A..."; } }</pre>

step3:在resource下添加META-INFO/services目錄
添加完這個(gè)目錄后,添加一個(gè)以 SaySomething接口的全限定名為名字的文件,這個(gè)文件的內(nèi)容是你要設(shè)置的具體實(shí)現(xiàn)類。這邊我們就設(shè)置實(shí)現(xiàn)類為上面的 ASaySomething。

step4:使用SPI機(jī)制

<pre class="java" style="margin: 10px 0px; padding: 0px; white-space: pre !important; word-wrap: break-word; position: relative !important;">

Copy

public static void main(String[] args) { ServiceLoader<SaySomething> loader = ServiceLoader.load(SaySomething.class); loader.forEach(item ->{item.say("csx");}); }</pre>

API和SPI的比較

在開(kāi)發(fā)中我們還經(jīng)常會(huì)提到API這個(gè)名詞,下面也總結(jié)下兩者的區(qū)別:

  • API (Application Programming Interface)在大多數(shù)情況下,都是實(shí)現(xiàn)方制定接口并完成對(duì)接口的實(shí)現(xiàn),調(diào)用方僅僅依賴接口調(diào)用,且無(wú)權(quán)選擇不同實(shí)現(xiàn)。 從使用人員上來(lái)說(shuō),API 直接被應(yīng)用開(kāi)發(fā)人員使用。

  • SPI (Service Provider Interface)是調(diào)用方來(lái)制定接口規(guī)范,提供給外部來(lái)實(shí)現(xiàn),調(diào)用方在調(diào)用時(shí)則選擇自己需要的外部實(shí)現(xiàn)。 從使用人員上來(lái)說(shuō),SPI 被框架擴(kuò)展人員使用。

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

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

  • 使用Java SPI機(jī)制的優(yōu)勢(shì)是實(shí)現(xiàn)解耦,使得第三方服務(wù)模塊的裝配控制的邏輯與調(diào)用者的業(yè)務(wù)代碼分離,而不是耦合在一起。應(yīng)用程序可以根據(jù)實(shí)際業(yè)務(wù)情況啟用框架擴(kuò)展或替換框架組件

缺點(diǎn)

  • SPI必須先將接口的所有實(shí)現(xiàn)類都遍歷出來(lái)才能最后選擇具體使用哪個(gè)類。有些不要的類也會(huì)被實(shí)例化,可能會(huì)比較浪費(fèi)內(nèi)存。
  • ServiceLoader并不是線程安全的。

網(wǎng)頁(yè)名稱:作為一個(gè)Java工程師,你應(yīng)該要知道SPI機(jī)制
本文地址:http://bm7419.com/article0/pssjoo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計(jì)公司網(wǎng)站策劃、ChatGPT外貿(mào)網(wǎng)站建設(shè)、網(wǎng)站維護(hù)、網(wǎng)站制作

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

商城網(wǎng)站建設(shè)