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

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

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

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

SPI 概念

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

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

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

舉個(gè)栗子

上面說(shuō)了 SPI 的幾個(gè)概念,接下來(lái)阿粉就通過(guò)一個(gè)栗子來(lái)帶大家感受一下具體的用法。

第一步

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

package com.example.demo.spi;


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

第二步

再寫兩個(gè)對(duì)應(yīng)的實(shí)現(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)建一個(gè)名為 META-INF/services? 的文件夾,在其中創(chuàng)建一個(gè)名為 com.example.demo.spi.Compresser 的文件,其中的內(nèi)容如下:

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

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

圖片

第四步

有了上面的接口,實(shí)現(xiàn)類和配置文件,接下來(lái)我們就可以使用 ServiceLoader? 動(dòng)態(tài)加載實(shí)現(xiàn)類,來(lái)實(shí)現(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());
}
}
}

運(yùn)行的結(jié)果如下

圖片

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

原理

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

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

圖片

同時(shí)又因?yàn)樵谧x取文件的時(shí)候使用了 class? 的路徑名稱,因?yàn)槲覀兪褂?nbsp;load? 方法的時(shí)候只會(huì)傳遞一個(gè) class,所以我們的文件名也必須是接口的全路徑。

圖片

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

圖片

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

圖片

常用的框架

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

優(yōu)缺點(diǎn)

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

優(yōu)點(diǎn)

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

缺點(diǎn)

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

責(zé)任編輯:武曉燕 來(lái)源: Java極客技術(shù)
相關(guān)推薦

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-01-12 09:08:37

索引JavaReference對(duì)象

2011-04-27 09:30:48

企業(yè)架構(gòu)

2022-10-08 00:00:00

Spring數(shù)據(jù)庫(kù)項(xiàng)目

2020-03-05 10:28:19

MySQLMRR磁盤讀

2020-09-27 06:53:57

MavenCDNwrapper

2020-10-14 06:22:14

UWB技術(shù)感知

2010-11-01 01:25:36

Windows NT

2020-09-22 08:22:28

快充

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ū)塊鏈技術(shù)支付寶

2010-04-22 14:14:29

Live-USB

2020-08-04 14:20:20

數(shù)據(jù)湖Hadoop數(shù)據(jù)倉(cāng)庫(kù)

2021-09-01 23:29:37

Golang語(yǔ)言gRPC
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 国产中文原创 | 国产精品v | 亚洲国产精品91 | 日韩欧美在线视频一区 | 国产精品色av | 国产人久久人人人人爽 | 久在草| 一区二区三区播放 | 精品一区二区三区在线视频 | 日日摸日日碰夜夜爽亚洲精品蜜乳 | 一区二区在线 | 精品国产黄a∨片高清在线 成人区精品一区二区婷婷 日本一区二区视频 | 国产精品美女久久久av超清 | 久久久成| 日韩电影一区 | 日韩欧美国产一区二区 | 一区二区久久 | 亚洲第一免费播放区 | 99久久精品一区二区毛片吞精 | 国产精品无 | 欧美一级毛片久久99精品蜜桃 | 91精品久久久久久久久久小网站 | 欧美xxxx网站 | 成人午夜视频在线观看 | 成人亚洲精品 | 欧美成人二区 | 狠狠操电影 | 国产精品久久久久久久久免费 | 久久久久久久久久爱 | 婷婷国产一区 | 欧美性大战xxxxx久久久 | 天天干天天干 | a在线免费观看视频 | 欧美色综合一区二区三区 | 在线免费观看黄视频 | 二区中文 | 久久精品亚洲成在人线av网址 | 日本在线免费 | 中文字幕精品一区二区三区精品 | 国产日韩精品视频 | 中文字幕综合 |