SPI (Service Provider Interfaces), 中文直譯服務提供者接口,一種服務發現機制。可能不少人都不太熟悉這個機制,可是日常或多或少都用到了這個機制,好比咱們使用 JDBC 鏈接操做數據庫的時候。java
SPI 主要適用於功能擴展的場景,如一些框架提供某一部分功能能夠由第三方開發人員擴展,知足其自身業務需求。mysql
假設咱們在公司內實現了一個統一登錄框架,框架內部僅僅提供用戶名 / 密碼登錄方式。後來 A 部門想使用該框架,可是他們想增長微信登錄受權。正常狀況下,咱們能夠改動登錄框架代碼,增長微信登錄實現方式。若是後面又增長 QQ 登錄,淘寶登錄那?也只能不斷相應的實現。sql
這種狀況若是使用 SPI,能夠在不用改動框架代碼前提下,增長新的登錄實現方式。下面用代碼演示如何使用 SPI。數據庫
定義接口api
首先咱們新建一個 maven 項目 oauth-api
,在這個項目建立一個公共接口。微信
public interface OauthLoginService { void login(); }
第三方實現該接口框架
再新建一個 maven 項目 wechat-oauth
,引入上面 oauth-api
依賴maven
public class WechatLoginService implements OauthLoginService { @Override public void login() { System.out.println("使用微信登錄受權"); } }
定義配置文件ide
SPI 須要將接口實現定義在配置文件中,文件名爲接口全名稱,如 com.andyxh.OauthLoginService
,配置文件需放在 resources\META-INF\services 文件夾下。文件內容以下:插件
com.another.WechatLoginService
加載接口實現類
新建 maven 項目 oauth-login
, 在這個項目中引入 wechat-oauth
與 oauth-api
依賴。SPI 核心將會使用 java.util.ServiceLoader
讀取上面上面定義配置文件,加載全部服務實現類。使用代碼以下:
ServiceLoader<OauthLoginService> serviceLoader=ServiceLoader.load(OauthLoginService.class); serviceLoader.forEach(OauthLoginService::login);
打印結果:
使用微信登錄受權
上面說過 JDBC 中使用到 SPI 進制。JDK 定義標準數據庫接口,相應的數據庫廠商實現這類接口。以 mysql-connector-javal
爲例。
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.16</version> </dependency>
mysql jar 包 META-INF/services 中存在 java.sql.Driver
文件,這個文件定義了實現類。
com.mysql.cj.jdbc.Driver
能夠看到 java.sql.Driver
是標準 SPI 接口,而 com.mysql.cj.jdbc.Driver
是 mysql 標準實現接口。
什麼時候加載 java.sql.Driver
?
咱們將會使用 DriverManager.getConnection
獲取相應數據庫鏈接。這個類內部存在一個靜態代碼塊,將會使用 ServiceLoader
加載實現類。
static { loadInitialDrivers(); println("JDBC DriverManager initialized"); } private static void loadInitialDrivers() { .... ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class); Iterator<Driver> driversIterator = loadedDrivers.iterator(); try{ while(driversIterator.hasNext()) { driversIterator.next(); } } catch(Throwable t) { // Do nothing } return null; } .... }
ServiceLoader
一次性將會實例化全部實現,可是若是沒有某一擴展初始化耗時好久,可是卻不須要馬上使用,就會很是浪費資源。
基於這個問題, Dubbo SPI 機制改進 Java SPI 的不足,作到按需加載而且增長 ioc 與 aop 的功能,下篇文章能夠在具體聊聊,敬請期待。