日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

Java中SPI的一些理解

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

前言

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

什么是SPI

SPI全稱Service Provider Interface,字面意思是提供服務(wù)的接口,再解釋詳細(xì)一下就是Java提供的一套用來被第三方實現(xiàn)或擴(kuò)展的接口,實現(xiàn)了接口的動態(tài)擴(kuò)展,讓第三方的實現(xiàn)類能像插件一樣嵌入到系統(tǒng)中。

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

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

SPI示例

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

Java中SPI的一些理解

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

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

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

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

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

Java中SPI的一些理解

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

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

目錄結(jié)構(gòu)如下:

Java中SPI的一些理解

下面再創(chuàng)建一個用來測試的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>

創(chuàng)建測試類

/** * @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('參數(shù)'); } }}

執(zhí)行結(jié)果:

我是SpiTwoService:參數(shù)我是SpiOneService:參數(shù)

通過運(yùn)行結(jié)果我們可以看到,已經(jīng)將SpiInterfaceService接口的所有實現(xiàn)都加載到了當(dāng)前項目中,并且執(zhí)行了調(diào)用。

Java中SPI的一些理解

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

SPI的實現(xiàn)

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

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();我就明白是怎么回事了,這個就是線程上下文類加載器,因為線程上下文類加載器就是為了做類加載雙親委派模型的逆序而創(chuàng)建的。

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

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

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

Java中SPI的一些理解

hasNext()方法又主要調(diào)用了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(); // 如果當(dāng)前線程上下文類加載器為空,會用父類加載器(默認(rèn)是應(yīng)用程序類加載器) 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()方法中判斷當(dāng)前類是否已經(jīng)出現(xiàn)化的時候要用 nextName = pending.next(); return true; }

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

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

Java中SPI的一些理解

next()方法主要是nextService()實現(xiàn)的,那么繼續(xù)看nextService()方法。

private S nextService() { if (!hasNextService()) throw new NoSuchElementException(); String cn = nextName; nextName = null; Class<?> c = null; try { // 直接加載類,無需初始化(因為上面hasNext()已經(jīng)初始化了)。 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 }

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

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

以上就是Java中SPI的一些理解的詳細(xì)內(nèi)容,更多關(guān)于Java SPI的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Java
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
国产精品qvod| 石原莉奈在线亚洲二区| 久久黄色影视| 日韩精品免费视频一区二区三区| 亚洲影视一区| 亚洲精品日本| 欧美色综合网| 久久久久九九精品影院| 国产精品1luya在线播放| 美女性感视频久久| 日韩精品一页| 欧美日韩伊人| 国内精品美女在线观看| 日本а中文在线天堂| 日韩在线欧美| 尤物网精品视频| 亚洲免费福利一区| 欧美成a人片免费观看久久五月天| 日韩精品视频中文字幕| 国精品一区二区三区| 激情婷婷久久| 欧美专区18| 亚洲乱码一区| 欧美日韩一区二区三区不卡视频| 久久香蕉网站| 日韩免费一区| 欧美13videosex性极品| 在线一区视频观看| 午夜日韩av| 日韩综合一区二区| 日本在线成人| 亚洲理论在线| 日韩精品中文字幕第1页| 国产欧美日韩精品一区二区三区| 欧美国产另类| 欧美色综合网| 国产精品二区影院| 国产精品伊人| 国产亚洲字幕| 九九久久婷婷| 国产精品乱战久久久| 91精品一区二区三区综合在线爱| 久久午夜精品| 国产成人在线中文字幕| 婷婷久久免费视频| 中文日韩在线| 久久国产成人午夜av影院宅| 97精品国产| 国产精品白丝一区二区三区| 国产精选一区| 久久久男人天堂| 精品国产不卡| 国产精品巨作av| 今天的高清视频免费播放成人| 日韩视频一区| 欧美日韩视频免费看| 亚洲一级淫片| 自拍自偷一区二区三区| 亚洲欧洲专区| 日韩一区精品视频| 国精品一区二区| 激情综合自拍| 亚洲欧美日韩国产一区| 在线观看精品| 日本欧美在线看| 国产一区二区精品福利地址| 亚洲不卡系列| 日韩1区2区3区| 国产欧美日韩影院| 成人久久一区| 日韩另类视频| 日韩中文字幕无砖| 欧美日韩精品一区二区视频| 午夜久久av| 日韩欧美看国产| 亚洲三级国产| 欧美~级网站不卡| 国产日韩免费| 久久成人国产| 人人香蕉久久| 国产精品亚洲二区| 久久国产精品久久w女人spa| 成人国产精品一区二区免费麻豆| 午夜久久av| 欧美午夜不卡| 久久福利在线| 日韩精品午夜视频| 免费美女久久99| 欧美成人亚洲| 高清av不卡| 青草国产精品| 在线精品国产亚洲| 不卡视频在线| 五月天av在线| 国产一区精品福利| 日韩三级精品| 亚洲一区日本| 久久精品国产68国产精品亚洲| 精品国产欧美| 国产日韩免费| 免费日本视频一区| 久久国产尿小便嘘嘘| 亚洲尤物在线| 香蕉成人av| 成年男女免费视频网站不卡| 国产精品99久久久久久董美香| 日韩区欧美区| 中文字幕日韩高清在线| 亚洲a在线视频| 精品国产免费人成网站| 麻豆精品在线| 日本不卡不码高清免费观看| 一区二区视频欧美| 999国产精品999久久久久久| 国产一区二区三区久久久久久久久| 日韩av一区二| 激情丁香综合| 日韩精品永久网址| 国产一区二区三区亚洲| 老牛国内精品亚洲成av人片| 亚洲一二av| 午夜久久美女| 婷婷亚洲综合| 亚洲调教视频在线观看| 波多野结衣一区| 夜夜嗨一区二区三区| 久久xxxx| 日本一区免费网站| 91伊人久久| 国产精品香蕉| 国产亚洲精品精品国产亚洲综合| 91久久在线| 影院欧美亚洲| 综合激情网...| 婷婷成人av| 欧美久久香蕉| 中文字幕av亚洲精品一部二部| 日韩不卡一二三区| 久久av超碰| 91一区二区三区四区| 999久久久精品国产| 免费久久精品| 一本色道精品久久一区二区三区| 中文在线一区| 日日夜夜免费精品| 国产亚洲一区二区三区不卡| 男人操女人的视频在线观看欧美| 日韩欧美网址| 婷婷激情久久| 中文日韩欧美| 一区二区三区四区日韩| 日韩毛片一区| 日韩动漫一区| 精品久久久亚洲| 久久一区二区三区喷水| 美国三级日本三级久久99| 日韩av三区| 91欧美国产| 免费久久精品| 日韩高清中文字幕一区| 久久国产日韩欧美精品| 亚洲影视一区二区三区| 日韩国产欧美三级| 精品国产精品国产偷麻豆| 久久精品日韩欧美| 久久免费高清| 视频一区在线播放| 国产免费成人| 国产精品羞羞答答在线观看| 亚洲va中文在线播放免费| 美国三级日本三级久久99| 国产精品嫩模av在线| 日韩欧美字幕| 亚洲神马久久| 国产精品探花在线观看| 国产精品亚洲二区| 99精品在线| 精品淫伦v久久水蜜桃| 黄色aa久久| 欧美一区二区三区久久| 亚洲1区在线| 视频一区视频二区在线观看| 亚洲欧美日本日韩| 久久xxxx精品视频| 亚洲男女自偷自拍| aa国产精品| 精品国产亚洲日本| 亚洲欧洲高清| 中文字幕成人| 天堂av在线| 日韩国产高清在线| 国产精品美女在线观看直播| 亚洲成人av观看| 日韩有吗在线观看| а√天堂8资源中文在线| 亚洲日本三级| 激情五月色综合国产精品| 国产精品一线| 黄色av日韩| 欧美男人天堂|