SPI的全名為Service Provider Interface.這個是針對廠商或者外掛程式的。一般來說對於未知的實現或者對擴充開放的系統,通常會把一些東西抽象出來,抽象的各個模組,往往有很多不同的實現方案,比如日誌模組的方案,xml解析模組、jdbc模組的方案等。這個可以通過我們的抽象Factory 方法來理解這個含義,實現是可以又廠商或者開發人員自己實現。由於代碼上是處於上層的一個封裝者,是不會知道底層怎麼去實現,那麼只能通過spi的形式,讓上層知道應該調用哪個抽象的具體實現。所以這裡可以理解為某些jar包裡,為其他開發擴充調用使用的一種方式,可以為某個介面或服務,提供一個具體的實現。
主要用到ServiceLoader這個類,ServiceLoader通過讀取resources/META-INF/services/com.xxx.xxx.xxxService檔案下的xxxService的spi實作類別,通過反射擷取對應類執行個體,並調用對應方法。
public class SearchFactory { private SearchFactory() { } public static Search newSearch() { Search search = null; ServiceLoader<Search> serviceLoader = ServiceLoader.load(Search.class);//尋找spi的實現 Iterator<Search> searchs = serviceLoader.iterator(); if (searchs.hasNext()) { search = searchs.next(); } if (search == null) {//如果沒有spi實現,就是用預設的類對象實現 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); try { search = (Search) classLoader.loadClass(Search.defaultSearchClass).newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } return search; }}
使用情境有:
1、javax.xml.ws.spi.Provider,這個類可以使用另外的實現,如com.sun.xml.internal.ws.spi.ProviderImpl。
這裡需要在工程下的resources目錄,建一個META-INF/services目錄,然後建立一個檔案名稱為javax.xml.ws.spi.Provider,檔案內容為com.sun.xml.internal.ws.spi.ProviderImpl。如果對於spi沒有預設實現的,那麼將會報錯,這裡就需要按照以上格式進行添加。
關於spi的更多瞭解,大家可以查看我寫的一個簡單的代碼,非常簡單。多謝大家支援。
github代碼:https://github.com/zhuzhenke/java-spi-test