1. 程式人生 > >聽說過api,但是你聽說過spi嗎

聽說過api,但是你聽說過spi嗎

在空閒的時間中,總是喜歡去看看技術類的部落格,無意間看到spi這個玩意兒,作為一個有追求的程式設計師,對於每一個點都會去查檢視,看看這個點是否能幫助自己的應用構建的更加優雅、健壯和穩定。果然spi沒有讓我失望,下面介紹一下spi機制。

一、淺談api和spi的區別:

在OOP程式設計的過程中,為了降低系統的耦合性,模組之間和模組之間總是使用介面的方式進行通訊。

1.1、場景:

例如在我們的系統當中,針對於搜尋業務有很多的實現方案,①:基於xml檔案進行搜尋,②:基於資料庫進行搜尋,③:基於檔案檢索。但是我們在使用介面的時候必須要在程式碼中指定一種實現來完成搜尋功能。

1.2、問題:

請思考一種情況,現在搜尋業務需要第三方來實現,我們尚且都不知道第三方是如何實現的,那麼我們又如何指定實現類呢。

1.3、既然有問題,解決方案肯定會是有的:

我們要抓住問題的根源,上述問題中主要是:不能在程式中動態的指明介面的實現,缺乏服務的發現機制。java的spi即提供了這樣的一中機制:為某個介面尋找服務實現的機制,其思想類似ioc,就是將程式的控制權轉譯服務實現方,在模組話的程式設計中,這個是非常的重要的。

總結一下:利用api可以實現模組間的解耦,提高系統的靈活性。但是假若要對系統的模組進行擴充套件的時候,spi就會排上用場了。

二、目前spi的應用,看看這麼牛逼的機制到底有誰在為其背書:

  • dubbo中利用spi進行了擴充套件
  • springboot的自動裝配機制(spi的變形,檔案給出的是spring.factories,這個機制目前我也沒有詳細的研究)
  • jdbc 其實現都是交由各個廠商來實現的

三、呈上程式碼,進一步的瞭解:

  • ISearchSPI.java 類
package spi;
public interface ISearchSPI {
    /**
     * 依據關鍵字 keyWork來查詢使用者資訊
     * @param keyWork
     * @return
     */
    String search(String keyWork);
}
  • FileSearchImpl.java
package spi;
public class FileSearchImpl implements ISearchSPI{
    @Override
    public String search(String keyWork) {
        return "朕是文字搜尋";
    }
}
  • SpiderSearchImpl.java
package spi;
public class SpiderSearchImpl implements ISearchSPI{
    @Override
    public String search(String keyWork) {
        return "臣妾來自網路爬蟲 搜尋!!!";
    }
}
  • SPITest.java 測試類:
package spi;

import java.util.Iterator;
import java.util.ServiceLoader;

public class SPITest {

    public static void main(String[] args) {

        ServiceLoader<ISearchSPI> load = ServiceLoader.load(ISearchSPI.class);
        Iterator<ISearchSPI> iterator = load.iterator();
        while (iterator.hasNext()){
            ISearchSPI next = iterator.next();
            String spiTest = next.search("測試spi");
            System.out.println(spiTest);
        }
    }
}
  • spi實現的核心
在resources目錄下建立META-INF,在這個目錄下建立services資料夾,最後建spiISearchspi檔案(不要然和字尾),把實現spi的類的全路徑名稱寫出來
spi.FileSearchImpl
spi.SpiderSearchImpl

image.png

  • 測試結果:
    image.png
    看到上面的程式碼是不是很有一種很清爽的感覺,實際的實現部分完全是可插拔的,作為介面完全不用指名實現類呼叫,僅僅用下面的一行程式碼即可搞定。這樣的方式會大大的提高你的程式的可擴充套件性
ServiceLoader<ISearchSPI> load = ServiceLoader.load(ISearchSPI.class);

四、關於spi的思考:

學習到新的技能點,總是需要如何把它運用到以後的coding中,才能讓這個知識點更加的有意義,但是也要防止過猶不及的炫技。

在以後我們除了api的解耦方式之外,還可以提過spi的機制。這對於我們在程式設計中不同的組不同的部門之間的程式的通訊又有了一種新的機制。同時如果我們有機會進入基礎架構組的話,自寫框架的就有了一種新的擴充套件機制,可以通過spi機制來讓我們的框架可接受更多的外掛,做到完全可插拔的形式(目前dubbo就是這樣乾的)很容易形成一種生態(springboot現在不就是這樣的嗎),

用場景驅動的方式,講述能投看的懂能落地的技術。加入java技術進階交流群(570980002)一起純粹的討論技術(非培訓機構)。

部落格首發地址csdn:https://blog.csdn.net/weixin_42849915
簡書地址:https://www.jianshu.com/u/4b48be4cf59f
希望結識更多的大牛一同學習一同進步