成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java 中經(jīng)常被提到的 SPI 到底是什么?

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

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

SPI 概念

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

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

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

舉個栗子

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

第一步

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

package com.example.demo.spi;


public interface Compresser {
byte[] compress(byte[] bytes);
byte[] decompress(byte[] bytes);
}

第二步

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

package com.example.demo.spi.impl;

import com.example.demo.spi.Compresser;

import java.nio.charset.StandardCharsets;


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;


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 技術了,如下所示:

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());
}
}
}

運行的結果如下

圖片

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

原理

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

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

圖片

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

圖片

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

圖片

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

圖片

常用的框架

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

優(yōu)缺點

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

優(yōu)點

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

缺點

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

責任編輯:武曉燕 來源: Java極客技術
相關推薦

2024-11-11 10:15:04

CPULinux系統(tǒng)

2017-09-07 14:44:10

程序員

2018-02-01 09:26:12

面試算法題程序員

2023-10-11 08:29:54

volatileJava原子性

2019-03-06 14:26:31

Javascript面試前端

2022-10-08 00:00:00

Spring數(shù)據(jù)庫項目

2020-03-05 10:28:19

MySQLMRR磁盤讀

2022-01-12 09:08:37

索引JavaReference對象

2011-04-27 09:30:48

企業(yè)架構

2020-09-27 06:53:57

MavenCDNwrapper

2020-09-22 08:22:28

快充

2020-10-14 06:22:14

UWB技術感知

2010-11-01 01:25:36

Windows NT

2009-06-09 22:11:44

JavaScriptObject

2013-06-09 09:47:31

.NetPDBPDB文件

2021-09-03 09:12:09

Linux中斷軟件

2019-10-30 10:13:15

區(qū)塊鏈技術支付寶

2020-08-04 14:20:20

數(shù)據(jù)湖Hadoop數(shù)據(jù)倉庫

2010-04-22 14:14:29

Live-USB

2021-09-01 23:29:37

Golang語言gRPC
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产激情精品一区二区三区 | 久久999| 日韩精品一区二区三区在线观看 | 日本黄色大片免费 | 欧美日韩一区二区在线 | 日韩一区二区三区在线播放 | 久久99国产精一区二区三区 | 欧美国产日本一区 | 国产精品久久久久久久久久久久 | 成人久久18免费网站图片 | 国产精品久久久久久久久免费丝袜 | 日韩午夜电影 | 国产免费福利小视频 | 国产中文字幕网 | 在线观看亚洲欧美 | 欧美精品欧美精品系列 | 国产精品性做久久久久久 | 国产一级视频在线 | 亚洲免费网站 | 欧美一二区 | 欧美2区 | 九久久| 九七午夜剧场福利写真 | 夜久久 | 精品少妇一区二区三区在线播放 | 日韩精品在线免费观看 | 亚洲精品二区 | www视频在线观看 | 亚洲精品成人av久久 | 免费成人在线网站 | 午夜国产精品视频 | 成人免费影院 | 在线成人 | 91se在线| 亚洲男人天堂 | 欧美日韩一二区 | 激情欧美日韩一区二区 | 亚洲黄色av | 天天躁人人躁人人躁狂躁 | 午夜播放器在线观看 | 久久性色 |