開心一刻
今天去幼兒園接小侄女,路上聊起了天
小侄女:小叔,今天我吃東西被老師發現了
我:老師說了什么
小侄女:她說拿出來,跟小朋友一起分享
我:那你拿出來了嗎
小侄女一臉可憐的看向我,說道:沒有,我沒有那么多鼻屎

SPI
概念
SPI 全稱 Service Provider Interface ,直譯過來就是: 服務提供介面 ,是不是有點抽象?
簡單點理解,Java SPI 就是提供這樣的一個機制:為某個介面尋找服務實作的機制
還是抽象?我們往下看它的具體實作就好理解了
實作三板斧
1、介面與實作
Animal 介面

Dog 實作

Cat 實作

2、組態檔
組態檔有點講究,需要按這套規則來
2.1 在 src/main/resources/ 下建立目錄: /META-INF/services ,位置和名字都必須嚴格按這個來,一字都不能差
2.2 在 /META-INF/services 目錄下創建一個以介面全限定類名為名的檔案: com.qsl.service.Animal ,沒有額外的后綴
2.3 將介面實作類的全限定類名寫入到 2.2 創建的檔案中,一個實作占一行

3、ServiceLoader 加載
通過 ServiceLoader 進行加載,代碼很簡單,如下所示

正常情況下會輸出如下內容

示例工程結構如下

至此,對 SPI 的感覺是不是沒那么抽象了
簡單理解, Java SPI 是 基于介面的編程 + 策略模式 + 組態檔 實作的動態加載機制
使用場景
不太好概括,一千個人眼中有一千個哈姆雷特
但是我們可以通過一些案例來形成自己的概括
1、DriverManager
不知道大家還記得 JDBC 的寫法嗎

我們去跟下 DriverManager 的原始碼

我們再看下 MySQL 驅動的包結構

2、SLF4J
具體原始碼我就不帶大家去跟了,有興趣的可以去看看:從原始碼來理解slf4j的系結,以及logback對組態檔的加載 中的問題1
3、Spring SPI
Spring 有自己的 SPI 實作機制,和 JDK SPI 略有不同
Spring 是在 src/main/resources/META-INF 目錄下創建 spring.factories ,里面以鍵值對的方式存放多個實作,類似如下

4、Dubbo SPI
Dubbo 又有自己的一套實作,組態檔需要放到 META-INF/dubbo 目錄下
具體細節可查看其官方檔案:Dubbo SPI
問題重現
此刻,大家是不是覺得 JDK SPI 很簡單?
但正是這么簡單的東西,樓主都碰到了問題,如下圖所示

當時人就懵了!!!
問題排查
一度懷疑是不是 JDK SPI 還有額外的配置
因為是作業中的專案出了這個問題,所以我自建了一個 demo 來驗證 實作三板斧
結果 demo 的執行是沒問題的,這也就說明 JDK SPI 的實作就只有那三板斧,那問題出在哪了?
本著快速解決問題的目的,我換了一種實作方式,采用 Spring SPI
結果依然是有問題,同樣是讀不到 spring.factories 中的配置
正在一籌莫展之際,直覺告訴我是不是 maven 構建出了問題,所以我對專案進行了 package ,然后去看了下打好的包的目錄結構

META-INF 目錄下的 com.qsl.service.Animal 檔案了?
肯定是 pom.xml 配置不對

我是萬萬沒想到 pom.xml 會進行如上的配置(后面問了老同事,沒特別的原因,就是簡單的認為只會有 xml 和 yml 組態檔)
此刻,相信大家都知道怎么改了吧(去掉<includes>標簽,或者在<includes>中加上)
然而樓主沒用采用上述兩種方案的任一一個,也沒有改 pom.xml ,就問你氣不氣?
總結
1、 JDK SPI 的使用,就那三板斧,如果出了問題,不用想,肯定不是 JDK SPI 的問題
2、關于 SPI 的使用場景,樓主仍然不做概括(太菜,概括不好),大家自行去概括
3、關于 pom.xml
樓主之前寫過一篇:Maven pom.xml中的元素modules、parent、properties以及import
但就是沒講 <build> ,下次補上,你們記得提醒我哦!

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/482941.html
標籤:其他
