Java SPI簡單應(yīng)用案例詳解
開篇
本文主要談一下 Java SPI(Service Provider Interface) ,因為最近在看 Dubbo 的相關(guān)內(nèi)容,其中涉及到了 一個概念- Dubbo SPI, 最后又牽扯出來了 JAVA SPI, 所以先從 Java SPI 開整。
正文
平常學習一個知識點,我們的常規(guī)做法是:
- 是什么
- 有什么用
- 怎么用
這次我們倒著做,先不談什么是 SPI 及其作用,來看下如何使用。
使用
1. 創(chuàng)建一個 maven 工程
2. 創(chuàng)建一個接口類以及實現(xiàn)類
// 接口 public interface HelloService { void sayHello(); } // 實現(xiàn)類 1 public class HelloServiceImpl1 implements HelloService { @Override public void sayHello() { System.out.println("hello impl1"); } } // 實現(xiàn)類 2 public class HelloServiceImpl2 implements HelloService { @Override public void sayHello() { System.out.println("hello impl2"); } }
3. 創(chuàng)建一個 META-INF/services 文件夾,并添加一個文件
在 classpath 下面創(chuàng)建一個META-INF/services目錄,再在下面創(chuàng)建一個
以接口類全路徑名 命名的文件
即:com.nimo.spidemo.service.HelloService
4. 在第三步創(chuàng)建的文件中寫入如下內(nèi)容
寫入兩個實現(xiàn)類的全路徑名
com.nimo.spidemo.service.impl.HelloServiceImpl1 com.nimo.spidemo.service.impl.HelloServiceImpl2
5. 啟動函數(shù)
public class App { public static void main(String[] args) throws ClassNotFoundException, SQLException { // 方式 一 Iterator<HelloService> providers = Service.providers(HelloService.class); while(providers.hasNext()) { HelloService ser = providers.next(); ser.sayHello(); } System.out.println("-----------------分割線---------------"); // 方式 二 ServiceLoader<HelloService> load = ServiceLoader.load(HelloService.class); Iterator<HelloService> iterator = load.iterator(); while(iterator.hasNext()) { HelloService ser = iterator.next(); ser.sayHello(); } } }
運行結(jié)果如下:
hello impl1
hello impl2
-----------------分割線---------------
hello impl1
hello impl2
使用要素
針對上面的 demo,可以看出使用 Java SPI 的幾個關(guān)鍵要素:
- 接口類,比如 HelloService
- 對應(yīng)接口的實現(xiàn)類
實現(xiàn)類必須攜帶一個不帶參數(shù)的構(gòu)造方法 - 文件夾 META-INF/services
放置 classpath 目錄下 - 以“接口全限定名”命名的文件
- 文件內(nèi)容為接口實現(xiàn)類的全路徑
主程序通過java.util.ServiceLoder掃描META-INF/services下的配置文件,然后會找到實現(xiàn)類的全限定名,最后把類加載到JVM;
SPI 的作用
從上面的 demo 中可以看到,Java SPI 就是把某個接口的 指定實現(xiàn)類 (通過在指定文件配置的方式)給實例化出來了。
準確+官方的說:
SPI 是一種將服務(wù)接口與服務(wù)實現(xiàn)分離以達到解耦、大大提升了程序可擴展性的機制。引入服務(wù)提供者就是引入了 spi 接口的實現(xiàn)者,通過本地的注冊發(fā)現(xiàn)獲取到具體的實現(xiàn)類,輕松可插拔。
~~~ 如果還是不懂就接著往下看⬇️
SPI 的應(yīng)用場景
一個典型的案例就是 jdbc 。
數(shù)據(jù)庫各大廠商(如Mysql、Oracle)會根據(jù)一個統(tǒng)一的接口規(guī)范( java.sql.Driver )開發(fā)各自的驅(qū)動實現(xiàn)邏輯。
客戶端使用 jdbc 時不需要去改變代碼,直接引入不同的 spi 接口服務(wù)即可。
例如 :
Mysql 是 com.mysql.jdbc.Drive
Oracle 是 oracle.jdbc.driver.OracleDriver
一段熟悉的代碼:
使用操作 mysql 數(shù)據(jù)庫的前置工作:
//1.加載驅(qū)動程序 Class.forName("com.mysql.jdbc.Driver"); //2. 獲得數(shù)據(jù)庫連接 Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
當我們需要切到 oracle 數(shù)據(jù)庫時,更改驅(qū)動為 oracle.jdbc.driver.OracleDriver, 最后修改連接信息【用戶名,密碼等】即可。
總結(jié)
Java SPI 是一種服務(wù)發(fā)現(xiàn)機制。它通過在 classPath 路徑下的 META-INF/services 文件夾查找文件,自動加載文件里所定義的類。
它的核心關(guān)鍵作用就是 擴展。
其他應(yīng)用場景:
- 日志門面接口實現(xiàn)類加載
SLF4J加載不同提供商的日志實現(xiàn)類 - Spring
Spring中大量使用了 SPI,比如:對 servlet3.0 規(guī)范 ServletContainerInitializer 的實現(xiàn)、自動類型轉(zhuǎn)換Type Conversion SPI(Converter SPI、Formatter SPI)等 - Dubbo
Dubbo中也大量使用SPI的方式實現(xiàn)框架的擴展, 不過它對Java提供的原生SPI做了封裝,允許用戶擴展實現(xiàn)Filter接口
其中 Dubbo 中的 SPI 是接下來研究的重點。
到此這篇關(guān)于Java SPI簡單應(yīng)用案例詳解的文章就介紹到這了,更多相關(guān)Java SPI簡單應(yīng)用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java ArrayList的基本概念和作用及動態(tài)數(shù)組的機制與性能
在Java中,ArrayList是一個實現(xiàn)了List接口的動態(tài)數(shù)組,它可以根據(jù)需要自動增加大小,因此可以存儲任意數(shù)量的元素,這篇文章主要介紹了探秘Java ArrayList的基本概念和作用及動態(tài)數(shù)組的機制與性能,需要的朋友可以參考下2023-12-12Java實現(xiàn)Timer的定時調(diào)度函數(shù)schedule的四種用法
本文主要介紹了Java實現(xiàn)Timer的定時調(diào)度函數(shù)schedule的四種用法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-04-04Java中new Date().getTime()指定時區(qū)的時間戳問題小結(jié)
本文主要介紹了Java中new Date().getTime()時間戳問題小結(jié),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-07-07詳解Spring-Boot集成Spring session并存入redis
這篇文章主要介紹了詳解Spring-Boot集成Spring session并存入redis,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-05-05Javaweb實現(xiàn)在線人數(shù)統(tǒng)計代碼實例
這篇文章主要介紹了Javaweb實現(xiàn)在線人數(shù)統(tǒng)計代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-11-11Java類加載器與雙親委派機制和線程上下文類加載器專項解讀分析
類加載器負責讀取Java字節(jié)代碼,并轉(zhuǎn)換成java.lang.Class類的一個實例的代碼模塊。本文主要和大家聊聊JVM類加載器ClassLoader的使用,需要的可以了解一下2022-12-12