电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

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

Java中SPI的一些理解

瀏覽:3日期: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
相關文章:
主站蜘蛛池模板: 内六角扳手「厂家」-温州市威豪五金工具有限公司| 锤式粉碎机,医药粉碎机,锥式粉碎机-无锡市迪麦森机械制造有限公司 | 高空重型升降平台_高空液压举升平台_高空作业平台_移动式升降机-河南华鹰机械设备有限公司 | 电梯乘运质量测试仪_电梯安全评估测试仪-武汉懿之刻 | 合肥白癜风医院_[治疗白癜风]哪家好_合肥北大白癜风医院 | 2-羟基泽兰内酯-乙酰蒲公英萜醇-甘草查尔酮A-上海纯优生物科技有限公司 | 真空泵厂家_真空泵机组_水环泵_旋片泵_罗茨泵_耐腐蚀防爆_中德制泵 | 沥青灌缝机_路面灌缝机_道路灌缝机_沥青灌缝机厂家_济宁萨奥机械有限公司 | 防锈油-助焊剂-光学玻璃清洗剂-贝塔防锈油生产厂家 | 深圳侦探联系方式_深圳小三调查取证公司_深圳小三分离机构 | EFM 022静电场测试仪-套帽式风量计-静电平板监测器-上海民仪电子有限公司 | 不锈钢复合板|钛复合板|金属复合板|南钢集团安徽金元素复合材料有限公司-官网 | 粘度计NDJ-5S,粘度计NDJ-8S,越平水分测定仪-上海右一仪器有限公司 | 东莞市超赞电子科技有限公司 全系列直插/贴片铝电解电容,电解电容,电容器 | 开云(中国)Kaiyun·官方网站 - 登录入口| 珠海冷却塔降噪维修_冷却塔改造报价_凉水塔风机维修厂家- 广东康明节能空调有限公司 | 运动木地板厂家,篮球场木地板品牌,体育场馆木地板安装 - 欧氏运动地板 | 太原装修公司_山西整装家装设计_太原室内装潢软装_肖邦家居 | 铝板冲孔网,不锈钢冲孔网,圆孔冲孔网板,鳄鱼嘴-鱼眼防滑板,盾构走道板-江拓数控冲孔网厂-河北江拓丝网有限公司 | GEDORE扭力螺丝刀-GORDON防静电刷-CHEMTRONICS吸锡线-上海卓君电子有限公司 | 口臭的治疗方法,口臭怎么办,怎么除口臭,口臭的原因-口臭治疗网 | 钢绞线万能材料试验机-全自动恒应力两用机-混凝土恒应力压力试验机-北京科达京威科技发展有限公司 | 恒温恒湿试验箱_高低温试验箱_恒温恒湿箱-东莞市高天试验设备有限公司 | 玉米深加工设备-玉米深加工机械-新型玉米工机械生产厂家-河南粮院机械制造有限公司 | 钣金加工厂家-钣金加工-佛山钣金厂-月汇好 | PC构件-PC预制构件-构件设计-建筑预制构件-PC构件厂-锦萧新材料科技(浙江)股份有限公司 | 咖啡加盟-咖啡店加盟-咖啡西餐厅加盟-塞纳左岸咖啡西餐厅官网 | 动库网动库商城-体育用品专卖店:羽毛球,乒乓球拍,网球,户外装备,运动鞋,运动包,运动服饰专卖店-正品运动品网上商城动库商城网 - 动库商城 | 粘度计维修,在线粘度计,二手博勒飞粘度计维修|收购-天津市祥睿科技有限公司 | 有机肥设备生产制造厂家,BB掺混肥搅拌机、复合肥设备生产线,有机肥料全部加工设备多少钱,对辊挤压造粒机,有机肥造粒设备 -- 郑州程翔重工机械有限公司 | 恒温水槽与水浴锅-上海熙浩实业有限公司 | 西点培训学校_法式西点培训班_西点师培训_西点蛋糕培训-广州烘趣西点烘焙培训学院 | 安徽华耐泵阀有限公司-官方网站 安德建奇火花机-阿奇夏米尔慢走丝|高维|发那科-北京杰森柏汇 | YAGEO国巨电容|贴片电阻|电容价格|三星代理商-深圳市巨优电子有限公司 | 微学堂-电动能源汽车评测_电动车性能分享网 | 地磅-地秤-江阴/无锡地磅-江阴天亿计量设备有限公司_ | 传动滚筒,改向滚筒-淄博建凯机械科技有限公司 | 机房监控|动环监控|动力环境监控系统方案产品定制厂家 - 迈世OMARA | 石家庄小程序开发_小程序开发公司_APP开发_网站制作-石家庄乘航网络科技有限公司 | 金环宇|金环宇电线|金环宇电缆|金环宇电线电缆|深圳市金环宇电线电缆有限公司|金环宇电缆集团 | 证券新闻,热播美式保罗1984第二部_腾讯1080p-仁爱影院 |