SpringBoot詳細介紹SPI機制示例
簡介
SPI(Service Provider Interface)是JDK內(nèi)置的一種服務提供發(fā)現(xiàn)機制,可以用來啟用框架擴展和替換組件,主要用于框架中開發(fā),例如Dubbo、Spring、Common-Logging,JDBC等采用采用SPI機制,針對同一接口采用不同的實現(xiàn)提供給不同的用戶,從而提高了框架的擴展性。
Java SPI實現(xiàn)
Java內(nèi)置的SPI通過java.util.ServiceLoader類解析classPath和jar包的META-INF/services/目錄 下的以接口全限定名命名的文件,并加載該文件中指定的接口實現(xiàn)類,以此完成調(diào)用。
示例說明
創(chuàng)建動態(tài)接口
public interface VedioSPI
{
void call();
}實現(xiàn)類1
public class Mp3Vedio implements VedioSPI
{
@Override
public void call()
{
System.out.println("this is mp3 call");
}
}實現(xiàn)類2
public class Mp4Vedio implements VedioSPI
{
@Override
public void call()
{
System.out.println("this is mp4 call");
}
}在項目的source目錄下新建META-INF/services/目錄下,創(chuàng)建com.skywares.fw.juc.spi.VedioSPI文件。

相關測試
public class VedioSPITest
{
public static void main(String[] args)
{
ServiceLoader<VedioSPI> serviceLoader =ServiceLoader.load(VedioSPI.class);
serviceLoader.forEach(t->{
t.call();
});
}
}說明:Java實現(xiàn)spi是通過ServiceLoader來查找服務提供的工具類。
運行結(jié)果

源碼分析
上述只是通過簡單的示例來實現(xiàn)下java的內(nèi)置的SPI功能。其實現(xiàn)原理是ServiceLoader是Java內(nèi)置的用于查找服務提供接口的工具類,通過調(diào)用load()方法實現(xiàn)對服務提供接口的查找,最后遍歷來逐個訪問服務提供接口的實現(xiàn)類。

從源碼可以發(fā)現(xiàn):
- ServiceLoader類本身實現(xiàn)了Iterable接口并實現(xiàn)了其中的iterator方法,iterator方法的實現(xiàn)中調(diào)用了LazyIterator這個內(nèi)部類中的方法,解析完服務提供接口文件后最終結(jié)果放在了Iterator中返回,并不支持服務提供接口實現(xiàn)類的直接訪問。
- 所有服務提供接口的對應文件都是放置在META-INF/services/目錄下,final類型決定了PREFIX目錄不可變更。
雖然java提供的SPI機制的思想非常好,但是也存在相應的弊端。具體如下:
- Java內(nèi)置的方法方式只能通過遍歷來獲取
- 服務提供接口必須放到META-INF/services/目錄下。
針對java的spi存在的問題,Spring的SPI機制沿用的SPI的思想,但對其進行擴展和優(yōu)化。
Spring SPI
Spring SPI沿用了Java SPI的設計思想,Spring采用的是spring.factories方式實現(xiàn)SPI機制,可以在不修改Spring源碼的前提下,提供Spring框架的擴展性。
Spring示例
定義接口
public interface DataBaseSPI
{
void getConnection();
}相關實現(xiàn)
#DB2實現(xiàn)
public class DB2DataBase implements DataBaseSPI
{
@Override
public void getConnection()
{
System.out.println("this database is db2");
}
}
#Mysql實現(xiàn)
public class MysqlDataBase implements DataBaseSPI
{
@Override
public void getConnection()
{
System.out.println("this is mysql database");
}
}1.在項目的META-INF目錄下,新增spring.factories文件

2.填寫相關的接口信息,內(nèi)容如下
com.skywares.fw.juc.springspi.DataBaseSPI = com.skywares.fw.juc.springspi.DB2DataBase, com.skywares.fw.juc.springspi.MysqlDataBase
說明多個實現(xiàn)采用逗號分隔。
相關測試類
public class SpringSPITest
{
public static void main(String[] args)
{
List<DataBaseSPI> dataBaseSPIs =SpringFactoriesLoader.loadFactories(DataBaseSPI.class,
Thread.currentThread().getContextClassLoader());
for(DataBaseSPI datBaseSPI:dataBaseSPIs){
datBaseSPI.getConnection();
}
}
}
輸出結(jié)果

從示例中我們看出,Spring 采用spring.factories實現(xiàn)SPI與java實現(xiàn)SPI非常相似,但是spring的spi方式針對java的spi進行的相關優(yōu)化具體內(nèi)容如下:
- Java SPI是一個服務提供接口對應一個配置文件,配置文件中存放當前接口的所有實現(xiàn)類,多個服務提供接口對應多個配置文件,所有配置都在services目錄下;
- Spring factories SPI是一個spring.factories配置文件存放多個接口及對應的實現(xiàn)類,以接口全限定名作為key,實現(xiàn)類作為value來配置,多個實現(xiàn)類用逗號隔開,僅spring.factories一個配置文件。
那么spring是如何通過加載spring.factories來實現(xiàn)SpI的呢?我們可以通過源碼來進一步分析。
源碼分析

說明:loadFactoryNames解析spring.factories文件中指定接口的實現(xiàn)類的全限定名,具體實現(xiàn)如下:

說明: 獲取所有jar包中META-INF/spring.factories文件路徑,以枚舉值返回。 遍歷spring.factories文件路徑,逐個加載解析,整合factoryClass類型的實現(xiàn)類名稱,獲取到實現(xiàn)類的全類名稱后進行類的實例話操作,其相關源碼如下:

說明:實例化是通過反射來實現(xiàn)對應的初始化。
總結(jié)
本文詳細的講解了java和Spring的SPI機制,SPI技術(shù)將服務接口與服務實現(xiàn)進行分離實現(xiàn)解耦,從而提升程序的可擴展性。如有疑問,請隨時反饋。
到此這篇關于SpringBoot詳細介紹SPI機制示例的文章就介紹到這了,更多相關SpringBoot SPI機制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java Iterator迭代器與foreach循環(huán)代碼解析
這篇文章主要介紹了Java-Iterator迭代器與foreach循環(huán),主要包括Iterator迭代器接口的操作方法和foreach 循環(huán)語法解析,需要的朋友可以參考下2022-04-04
如何對?Excel?表格中提取的數(shù)據(jù)進行批量更新
這篇文章主要介紹了如何對Excel表格中提取的數(shù)據(jù)進行批量更新操作,本文通過示例代碼介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧2024-06-06
MySQL text類型對應mybatis jdbcType類型方式
這篇文章主要介紹了MySQL text類型對應mybatis jdbcType類型方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-07-07
Java面試之如何實現(xiàn)10億數(shù)據(jù)判重
當數(shù)據(jù)量比較大時,使用常規(guī)的方式來判重就不行了,所以這篇文章小編主要來和大家介紹一下Java實現(xiàn)10億數(shù)據(jù)判重的相關方法,希望對大家有所幫助2024-02-02
Spring?Boot項目中使用?TrueLicense?生成和驗證License的詳細步驟
這篇文章主要介紹了Spring?Boot項目中使用?TrueLicense?生成和驗證License,本文分步驟給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-10-10

