亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

一文搞懂Java SPI機制的原理與使用

 更新時間:2022年10月09日 09:14:12   作者:鴨血粉絲Tang  
Java 程序員在日常工作中經(jīng)常會聽到 SPI,而且很多框架都使用了 SPI 的技術(shù),那么問題來了,到底什么是 SPI 呢?今天小編就帶大家好好了解一下 SPI

Java 程序員在日常工作中經(jīng)常會聽到 SPI,而且很多框架都使用了 SPI 的技術(shù),那么問題來了,到底什么是 SPI 呢?今天阿粉就帶大家好好了解一下 SPI。

SPI 概念

SPI 全稱是 Service Provider Interface,是一種 JDK 內(nèi)置的動態(tài)加載實現(xiàn)擴展點的機制,通過 SPI 技術(shù)我們可以動態(tài)獲取接口的實現(xiàn)類,不用自己來創(chuàng)建。

這里提到了接口和實現(xiàn)類,那么 SPI 技術(shù)上具體有哪些技術(shù)細(xì)節(jié)呢?

  • 接口:需要有一個功能接口;
  • 實現(xiàn)類:接口只是規(guī)范,具體的執(zhí)行需要有實現(xiàn)類才行,所以不可缺少的需要有實現(xiàn)類;
  • 配置文件:要實現(xiàn) SPI 機制,必須有一個與接口同名的文件存放于類路徑下面的  META-INF/services 文件夾中,并且文件中的每一行的內(nèi)容都是一個實現(xiàn)類的全路徑;
  • 類加載器 ServiceLoaderJDK 內(nèi)置的一個類加載器,用于加載配置文件中的實現(xiàn)類;

舉個栗子

上面說了 SPI 的幾個概念,接下來阿粉就通過一個栗子來帶大家感受一下具體的用法。

第一步

創(chuàng)建一個接口,這里我們創(chuàng)建一個解壓縮的接口,其中定義了壓縮和解壓的兩個方法。

package?com.example.demo.spi;

/**
?*?<br>
?*?<b>Function:</b><br>
?*?<b>Author:</b>@author?ziyou<br>
?*?<b>Date:</b>2022-10-08 21:31<br>
?*?<b>Desc:</b>無<br>
?*/
public?interface?Compresser?{
??byte[]?compress(byte[]?bytes);
??byte[]?decompress(byte[]?bytes);
}

第二步

再寫兩個對應(yīng)的實現(xiàn)類,分別是 GzipCompresser.java 和 WinRarCompresser.java 代碼如下

package?com.example.demo.spi.impl;

import?com.example.demo.spi.Compresser;

import?java.nio.charset.StandardCharsets;

/**
?*?<br>
?*?<b>Function:</b><br>
?*?<b>Author:</b>@author?ziyou<br>
?*?<b>Date:</b>2022-10-08 21:33<br>
?*?<b>Desc:</b>無<br>
?*/
public?class?GzipCompresser?implements?Compresser?{
??@Override
??public?byte[]?compress(byte[]?bytes)?{
????return"compress?by?Gzip".getBytes(StandardCharsets.UTF_8);
??}
??@Override
??public?byte[]?decompress(byte[]?bytes)?{
????return?"decompress?by?Gzip".getBytes(StandardCharsets.UTF_8);
??}
}
package?com.example.demo.spi.impl;

import?com.example.demo.spi.Compresser;

import?java.nio.charset.StandardCharsets;

/**
?*?

?*?<b>Function:</b>

?*?<b>Author:</b>@author?ziyou

?*?<b>Date:</b>2022-10-08 21:33

?*?<b>Desc:</b>無

?*/
public?class?WinRarCompresser?implements?Compresser?{
??@Override
??public?byte[]?compress(byte[]?bytes)?{
????return?"compress?by?WinRar".getBytes(StandardCharsets.UTF_8);
??}

??@Override
??public?byte[]?decompress(byte[]?bytes)?{
????return?"decompress?by?WinRar".getBytes(StandardCharsets.UTF_8);
??}
}

第三步

創(chuàng)建配置文件,我們接著在 resources 目錄下創(chuàng)建一個名為 META-INF/services 的文件夾,在其中創(chuàng)建一個名為 com.example.demo.spi.Compresser 的文件,其中的內(nèi)容如下:

com.example.demo.spi.impl.WinRarCompresser
com.example.demo.spi.impl.GzipCompresser

注意該文件的名稱必須是接口的全路徑,文件里面的內(nèi)容每一行都是一個實現(xiàn)類的全路徑,多個實現(xiàn)類就寫在多行里面,效果如下。

第四步

有了上面的接口,實現(xiàn)類和配置文件,接下來我們就可以使用 ServiceLoader 動態(tài)加載實現(xiàn)類,來實現(xiàn) SPI 技術(shù)了,如下所示:

package?com.example.demo;

import?com.example.demo.spi.Compresser;

import?java.nio.charset.StandardCharsets;
import?java.util.ServiceLoader;

public?class?TestSPI?{
??public?static?void?main(String[]?args)?{
????ServiceLoader<Compresser>?compressers?=?ServiceLoader.load(Compresser.class);
????for?(Compresser?compresser?:?compressers)?{
??????System.out.println(compresser.getClass());
????}
??}
}

運行的結(jié)果如下

可以看到我們正常的獲取到了接口的實現(xiàn)類,并且可以直接使用實現(xiàn)類的解壓縮方法。

原理

知道了如何使用 SPI 接下來我們來研究一下是如何實現(xiàn)的,通過上面的測試我們可以看到,核心的邏輯是 ServiceLoader.load() 方法,這個方法有點類似于 Spring 中的根據(jù)接口獲取所有實現(xiàn)類一樣。

點開 ServiceLoader 我們可以看到有一個常量 PREFIX,如下所示,這也是為什么我們必須在這個路徑下面創(chuàng)建配置文件,因為 JDK 代碼里面會從這個路徑里面去讀取我們的文件。

同時又因為在讀取文件的時候使用了 class 的路徑名稱,因為我們使用 load 方法的時候只會傳遞一個 class,所以我們的文件名也必須是接口的全路徑。

通過 load 方法我們可以看到底層構(gòu)造了一個 java.util.ServiceLoader.LazyIterator 迭代器。

在迭代器中的 parse 方法中,就獲取了配置文件中的實現(xiàn)類名稱集合,然后在通過反射創(chuàng)建出具體的實現(xiàn)類對象存放到 LinkedHashMap<String,S> providers = new LinkedHashMap<>(); 中。

常用的框架

SPI 技術(shù)的使用非常廣泛,比如在 Dubble,不過 Dubble 中的 SPI 有經(jīng)過改造的,還有我們很常見的數(shù)據(jù)庫的驅(qū)動中也使用了 SPI,感興趣的小伙伴可以去翻翻看,還有 SLF4J 用來加載不同提供商的日志實現(xiàn)類以及 Spring 框架等。

優(yōu)缺點

前面介紹了 SPI 的原理和使用,那 SPI 有什么優(yōu)缺點呢?

優(yōu)點

優(yōu)點當(dāng)然是解耦,服務(wù)方只要定義好接口規(guī)范就好了,具體的實現(xiàn)可以由不同的 Jar 進行實現(xiàn),只要按照規(guī)范實現(xiàn)功能就可以被直接拿來使用,在某些場合會被進行熱插拔使用,實現(xiàn)了解耦的功能。

缺點

一個很明顯的缺點那就是做不到按需加載,通過源碼我們看到了是會將所有的實現(xiàn)類都進行創(chuàng)建的,這種做法會降低性能,如果某些實現(xiàn)類實現(xiàn)很耗時了話將影響加載時間。同時實現(xiàn)類的命名也沒有規(guī)范,讓使用者不方便引用。

到此這篇關(guān)于一文搞懂Java SPI機制的原理與使用的文章就介紹到這了,更多相關(guān)Java SPI機制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring Boot(五)之跨域、自定義查詢及分頁

    Spring Boot(五)之跨域、自定義查詢及分頁

    這篇文章主要介紹了Spring Boot(五)之跨域、自定義查詢及分頁的的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • Flink自定義Sink端實現(xiàn)過程講解

    Flink自定義Sink端實現(xiàn)過程講解

    這篇文章主要介紹了Flink自定義Sink端實現(xiàn)過程,在Fink官網(wǎng)中sink端只是給出了常規(guī)的write api.在我們實際開發(fā)場景中需要將flink處理的數(shù)據(jù)寫入kafka,hbase kudu等外部系統(tǒng)
    2023-01-01
  • Java方法能定義多少個參數(shù)你知道嗎

    Java方法能定義多少個參數(shù)你知道嗎

    這篇文章主要給大家介紹了關(guān)于Java方法能定義多少個參數(shù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用java具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-09-09
  • java File類的基本使用方法總結(jié)

    java File類的基本使用方法總結(jié)

    這篇文章主要介紹了java File類的基本使用方法總結(jié),為大家分享了java實現(xiàn)上傳代碼,感興趣的小伙伴們可以參考一下
    2016-04-04
  • Debian 7 和 Debian 8 用戶安裝 Java 8的方法

    Debian 7 和 Debian 8 用戶安裝 Java 8的方法

    Oracle Java 8 穩(wěn)定版本近期已發(fā)布,有很多新的特征變化。其中,有功能的程序支持通過“Lambda項目 ”,收到了一些安全更新和界面改進上的bug修復(fù),使得開發(fā)人員的工作更容易。
    2014-03-03
  • JVM運行時數(shù)據(jù)區(qū)原理解析

    JVM運行時數(shù)據(jù)區(qū)原理解析

    這篇文章主要介紹了JVM運行時數(shù)據(jù)區(qū)原理解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-08-08
  • mybatis打印SQL,并顯示參數(shù)的實例

    mybatis打印SQL,并顯示參數(shù)的實例

    這篇文章主要介紹了mybatis打印SQL,并顯示參數(shù)的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • JAVA中excel導(dǎo)出一對多合并具體實現(xiàn)

    JAVA中excel導(dǎo)出一對多合并具體實現(xiàn)

    項目中經(jīng)常會使用到導(dǎo)出功能,有導(dǎo)出Word,有導(dǎo)出Excel的,下面這篇文章主要給大家介紹了關(guān)于JAVA中excel導(dǎo)出一對多合并具體實現(xiàn)的相關(guān)資料,需要的朋友可以參考下
    2023-09-09
  • Java觀察者模式的深入了解

    Java觀察者模式的深入了解

    這篇文章主要為大家介紹了Java觀察者模式,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01
  • java 使用線程做的一個簡單的ATM存取款實例代碼

    java 使用線程做的一個簡單的ATM存取款實例代碼

    線程 Thread 類,和 Runable 接口 比較兩者的特點和應(yīng)用領(lǐng)域.可以,直接繼承線程Thread類。該方法編寫簡單,可以直接操作線程,適用于單重繼承情況,因而不能在繼承其他類,下面我們來看一個實例
    2013-08-08

最新評論