成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

您的位置:首頁技術文章
文章詳情頁

Java中SPI的一些理解

瀏覽:2日期:2022-08-19 17:55:40

前言

最近在面試的時候被問到SPI了,沒回答上來,主要也是自己的原因,把自己給帶溝里去了,因為講到了類加載器的雙親委派模型,后面就被問到了有哪些是破壞了雙親委派模型的場景,然后我就說到了SPI,JNDI,以及JDK9的模塊化都破壞了雙親委派。然后就被問,那你說說對Java中的SPI的理解吧。然后我就一臉懵逼了,之前只是知道它會破壞雙親委派,也知道是個怎么回事,但是并沒有深入了解,那么這次我就好好的來總結一下這個知識吧。

什么是SPI

SPI全稱Service Provider Interface,字面意思是提供服務的接口,再解釋詳細一下就是Java提供的一套用來被第三方實現或擴展的接口,實現了接口的動態擴展,讓第三方的實現類能像插件一樣嵌入到系統中。

咦。。。這個解釋感覺還是有點繞口。那就說一下它的本質。

將接口的實現類的全限定名配置在文件中(文件名是接口的全限定名),由服務加載器讀取配置文件,加載實現類。實現了運行時動態為接口替換實現類。

SPI示例

還是舉例說明吧。我們創建一個項目,然后創建一個module叫spi-interface。

Java中SPI的一些理解

在這個module中我們定義一個接口:

/** * @author jimoer **/public interface SpiInterfaceService { /** * 打印參數 * @param parameter 參數 */ void printParameter(String parameter);}

再定義一個module,名字叫spi-service-one,pom.xml中依賴spi-interface。在spi-service-one中定義一個實現類,實現SpiInterfaceService 接口。

package com.jimoer.spi.service.one;import com.jimoer.spi.app.SpiInterfaceService;/** * @author jimoer **/public class SpiOneService implements SpiInterfaceService { /** * 打印參數 * * @param parameter 參數 */ @Override public void printParameter(String parameter) { System.out.println('我是SpiOneService:'+parameter); }}

然后再spi-service-one的resources目錄下創建目錄META-INF/services,在此目錄下創建一個文件名稱為SpiInterfaceService接口的全限定名稱,文件內容寫入SpiOneService這個實現類的全限定名稱。效果如下:

Java中SPI的一些理解

再創建一個module,名稱為:spi-service-one,也是依賴spi-interface,并且定義一個實現類SpiTwoService 來實現SpiInterfaceService 接口。

package com.jimoer.spi.service.two;import com.jimoer.spi.app.SpiInterfaceService;/** * @author jimoer **/public class SpiTwoService implements SpiInterfaceService { /** * 打印參數 * * @param parameter 參數 */ @Override public void printParameter(String parameter) { System.out.println('我是SpiTwoService:'+parameter); }}

目錄結構如下:

Java中SPI的一些理解

下面再創建一個用來測試的module,名為:spi-app。

Java中SPI的一些理解

pom.xml中依賴spi-service-one和spi-service-two

<dependencies> <dependency> <groupId>com.jimoer.spi</groupId> <artifactId>spi-service-one</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>com.jimoer.spi</groupId> <artifactId>spi-service-two</artifactId> <version>1.0-SNAPSHOT</version> </dependency></dependencies>

創建測試類

/** * @author jimoer **/public class SpiService { public static void main(String[] args) { ServiceLoader<SpiInterfaceService> spiInterfaceServices = ServiceLoader.load(SpiInterfaceService.class); Iterator<SpiInterfaceService> iterator = spiInterfaceServices.iterator(); while (iterator.hasNext()){ SpiInterfaceService sip = iterator.next(); sip.printParameter('參數'); } }}

執行結果:

我是SpiTwoService:參數我是SpiOneService:參數

通過運行結果我們可以看到,已經將SpiInterfaceService接口的所有實現都加載到了當前項目中,并且執行了調用。

Java中SPI的一些理解

這整個代碼結構我們可以看出SPI機制將模塊的裝配放到了程序外面,就是說,接口的實現可以在程序外面,只需要在使用的時候指定具體的實現。并且動態的加載到自己的項目中。SPI機制的主要目的:一是為了解耦,將接口和具體實現分離開來;二是提高框架的擴展性。以前寫程序的時候,接口和實現都寫在一起,調用方在使用的時候依賴接口來進行調用,無權選擇使用具體的實現類。

SPI的實現

那么我們來看一下SPI具體是如何實現的呢?通過上面的例子,我們可以看到,SPI機制的核心代碼是下面這段:

ServiceLoader<SpiInterfaceService> spiInterfaceServices = ServiceLoader.load(SpiInterfaceService.class);

那么我們來看一下ServiceLoader.load()方法的源碼:

public static <S> ServiceLoader<S> load(Class<S> service) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); return ServiceLoader.load(service, cl);}

看到Thread.currentThread().getContextClassLoader();我就明白是怎么回事了,這個就是線程上下文類加載器,因為線程上下文類加載器就是為了做類加載雙親委派模型的逆序而創建的。

使用這個線程上下文類加載器去加載所需的SPI服務代碼,這是一種父類加載器去請求子類加載器完成類加載的行為,這種行為實際上是打通了,雙親委派模型的層次結構來逆向使用類加載器,已經違背了雙親委派模型的一般性原則,但也是無可奈何的事情。《深入理解Java虛擬機(第三版)》

雖然知道了它是破壞雙親委派的了,但是具體實現,還是需要具體往下看的。

在ServiceLoader里找到具體實現hasNext()的方法了,那么繼續來看這個方法的實現。

Java中SPI的一些理解

hasNext()方法又主要調用了hasNextService()方法。

// 固定路徑private static final String PREFIX = 'META-INF/services/';private boolean hasNextService() { if (nextName != null) { return true; } if (configs == null) { try { // 固定路徑+接口全限定名稱 String fullName = PREFIX + service.getName(); // 如果當前線程上下文類加載器為空,會用父類加載器(默認是應用程序類加載器) if (loader == null) configs = ClassLoader.getSystemResources(fullName); else configs = loader.getResources(fullName); } catch (IOException x) { fail(service, 'Error locating configuration files', x); } } while ((pending == null) || !pending.hasNext()) { if (!configs.hasMoreElements()) { return false; } pending = parse(service, configs.nextElement()); } // 后面next()方法中判斷當前類是否已經出現化的時候要用 nextName = pending.next(); return true; }

主要就是去加載META-INF/services/路徑下的接口全限定名稱的文件然后去里面找到實現類的類路徑將實現類進行類加載。

繼續看迭代器是如何取出每一個實現對象的。那就要看ServiceLoader中實現了迭代器的next()方法了。

Java中SPI的一些理解

next()方法主要是nextService()實現的,那么繼續看nextService()方法。

private S nextService() { if (!hasNextService()) throw new NoSuchElementException(); String cn = nextName; nextName = null; Class<?> c = null; try { // 直接加載類,無需初始化(因為上面hasNext()已經初始化了)。 c = Class.forName(cn, false, loader); } catch (ClassNotFoundException x) { fail(service, 'Provider ' + cn + ' not found'); } if (!service.isAssignableFrom(c)) { fail(service, 'Provider ' + cn + ' not a subtype'); } try { // 將加載好的類實例化出對象。 S p = service.cast(c.newInstance()); providers.put(cn, p); return p; } catch (Throwable x) { fail(service, 'Provider ' + cn + ' could not be instantiated', x); } throw new Error(); // This cannot happen }

看到這里就可以明白了,是如何創建出對象的了。先在hasNext()將接口的實現類進行加載并判斷是否存在接口的實現類,然后在next()方法中將實現類進實例化。

Java中使用SPI機制的功能其實有很多,像JDBC、JNDI、以及Spring中也有使用,甚至RPC框架(Dubbo)中也有使用SPI機制來實現功能。

以上就是Java中SPI的一些理解的詳細內容,更多關于Java SPI的資料請關注好吧啦網其它相關文章!

標簽: Java
相關文章:
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
欧美区一区二区三区| 久久久久久久久一区二区| 亚洲人成人一区二区三区| 精品久久久网站| 国产一区二区视频在线播放| 亚洲美女一区| 国产精品久久久久久久久果冻传媒| 国产一区二区剧情av在线| 国产日韩欧美二区| 国产精品乱码妇女bbbb| 91在线精品一区二区三区| 日韩欧美在线一区二区三区| 极品销魂美女一区二区三区| 在线观看不卡视频| 日本美女一区二区| 久久久久高清| 亚洲一区电影777| 日韩一级不卡| 亚洲同性同志一二三专区| 欧美日韩在线高清| 国产女人18毛片水真多成人如厕 | 精品国产伦一区二区三区观看体验| 亚洲与欧洲av电影| 午夜视频久久久| 日韩精品一区二区三区中文精品| 337p日本欧洲亚洲大胆色噜噜| 一本久久精品一区二区| 欧美一区二区三区视频免费播放| 6080yy午夜一二三区久久| 日韩欧美中文字幕公布| 亚洲国产成人高清精品| 欧美伦理影视网| 2023国产精品自拍| 成人av网站在线| 精品福利在线导航| 91网址在线看| 国模冰冰炮一区二区| 丝袜美腿亚洲色图| 色综合久久99| 麻豆成人在线观看| 555www色欧美视频| 波多野结衣亚洲| 久久久亚洲欧洲日产国码αv| 欧美一区国产一区| 中文字幕亚洲精品在线观看| 欧美色一级片| 亚洲激情在线播放| 欧美亚洲免费| 同产精品九九九| 欧美日韩中文字幕精品| 国产乱子轮精品视频| 日韩视频免费观看高清在线视频| 成人免费毛片嘿嘿连载视频| 久久亚洲综合色一区二区三区| 欧美色123| 亚洲国产精品久久艾草纯爱| 欧美日韩一区二区在线观看视频| 成人污视频在线观看| 国产精品久久久久久久裸模| 亚洲视频导航| 肉丝袜脚交视频一区二区| 欧美日韩亚洲综合在线| 成人福利视频网站| 国产精品污网站| 亚洲深夜av| 国产呦精品一区二区三区网站| 日韩欧美一级片| 国产一区亚洲| 天堂成人免费av电影一区| 欧美裸体一区二区三区| 91玉足脚交白嫩脚丫在线播放| 亚洲同性同志一二三专区| 91成人免费在线视频| 本田岬高潮一区二区三区| 亚洲精品高清在线| 欧美日韩电影一区| 欧美在线看片| 亚洲成人一区二区| 欧美日本一道本| 97精品久久久午夜一区二区三区| 亚洲乱码日产精品bd| 欧美视频自拍偷拍| 91老司机福利 在线| 亚洲国产精品人人做人人爽| 6080国产精品一区二区| 亚洲国产高清在线观看视频| 国产精品国产a级| 久久这里只精品最新地址| 欧美日韩日本网| 偷拍亚洲欧洲综合| 亚洲精品国产精品乱码不99| 国产精品理伦片| 久久久久久久久一区二区| 91碰在线视频| 女人天堂亚洲aⅴ在线观看| 欧美日韩三级电影在线| 欧美日韩成人一区二区三区| 菠萝蜜视频在线观看一区| 国产一区日韩欧美| 91高清视频在线| 久久无码av三级| 亚洲一区二区三区四区的| 国产一区二区导航在线播放| 亚洲天堂偷拍| 99热免费精品在线观看| 久久久久99| 欧美日韩不卡视频| 中文字幕亚洲综合久久菠萝蜜| 国产亚洲欧美色| 性做久久久久久免费观看| 精品欧美久久久| 日韩一级精品| 成人动漫精品一区二区| 亚洲国产精品久久久久秋霞影院| 亚洲精品一区二区三区四区高清| 午夜综合激情| 欧美一区免费视频| 久久国产婷婷国产香蕉| 日韩美女啊v在线免费观看| 在线不卡一区二区| 亚洲视频大全| 91麻豆免费视频| 久久国产精品一区二区| 国产精品国产三级国产aⅴ原创| 欧美日韩第一区日日骚| 国产精品入口| 欧美成人一区二免费视频软件| 久久超碰97中文字幕| 亚洲一区自拍偷拍| 国产欧美一区视频| 欧美一级二级三级蜜桃| 不卡的av中国片| 麻豆传媒一区二区三区| 一区二区视频免费在线观看| 精品sm捆绑视频| 欧美三级中文字幕在线观看| 最新日韩av| 波多野结衣91| 久久精品国产99国产| 一区二区三区资源| 久久久国产精品不卡| 在线观看免费成人| 国产精品一区在线播放| 国产字幕视频一区二区| www.欧美精品一二区| 男女男精品视频网| 亚洲午夜三级在线| 亚洲欧洲精品一区二区三区不卡| 69堂精品视频| 久久青青草综合| 日韩午夜av在线| 欧美日韩免费观看一区| 成人精品国产免费网站| 蜜桃视频在线一区| 亚洲国产日韩在线一区模特| 一色桃子久久精品亚洲| 久久久久久一二三区| 欧美一区二区三区视频| 欧美色视频在线观看| 久久国产精品免费一区| 亚洲图片在线| 欧美 亚欧 日韩视频在线| 成人av在线一区二区三区| 久久爱另类一区二区小说| 日本女人一区二区三区| 亚洲国产精品一区二区www在线| 中文字幕亚洲区| 国产精品视频第一区| 久久综合久久综合久久| 日韩欧美国产成人一区二区| 在线播放国产精品二区一二区四区| 一本一道久久a久久精品 | 国产一区二区不卡| 久久99精品久久久久| 蜜桃av噜噜一区| 琪琪久久久久日韩精品| 青青草原综合久久大伊人精品| 日韩激情在线观看| 日本v片在线高清不卡在线观看| 天天综合日日夜夜精品| 久久久美女艺术照精彩视频福利播放| 欧美精品成人一区二区三区四区| 欧美三级日韩在线| 欧美色图第一页| 欧美日本免费一区二区三区| 欧美日韩成人一区二区| 在线看不卡av| 在线观看中文字幕不卡| 久久久噜噜噜| 欧美在线综合| 欧美午夜视频| 亚洲国产一区二区三区在线播| 亚洲美女少妇无套啪啪呻吟| 亚洲精品乱码久久久久久蜜桃麻豆 | 精品久久久久久亚洲综合网| 欧美电影免费观看高清完整版在线观看| 欧美r级在线观看| 日韩精品一区在线观看| 久久综合色天天久久综合图片| 久久久久久免费网|