Java 中经常被提到的 SPI 到底是什么?

Java 程序员在日常工作中经常会听到 SPI,而且很多框架都使用了 SPI 的技术,那么问题来了,到底什么是 SPI 呢?今天阿粉就带大家好好了解一下 SPI。

SPI 概念

SPI 全称是 Service Provider Interface,是一种 JDK 内置的动态加载实现扩展点的机制,通过 SPI 技术我们可以动态获取接口的实现类,不用自己来创建。

这里提到了接口和实现类,那么 SPI 技术上具体有哪些技术细节呢?

  1. 接口:需要有一个功能接口;
  2. 实现类:接口只是规范,具体的执行需要有实现类才行,所以不可缺少的需要有实现类;
  3. 配置文件:要实现 SPI 机制,必须有一个与接口同名的文件存放于类路径下面的 META-INF/services 文件夹中,并且文件中的每一行的内容都是一个实现类的全路径;
  4. 类加载器 ServiceLoaderJDK 内置的一个类加载器,用于加载配置文件中的实现类;

举个栗子

上面说了 SPI 的几个概念,接下来阿粉就通过一个栗子来带大家感受一下具体的用法。

第一步

创建一个接口,这里我们创建一个解压缩的接口,其中定义了压缩和解压的两个方法。

package com.example.demo.spi;

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

第二步

再写两个对应的实现类,分别是 GzipCompresser.javaWinRarCompresser.java 代码如下

package com.example.demo.spi.impl;

import com.example.demo.spi.Compresser;

import java.nio.charset.StandardCharsets;

/**
 *
 * Function:
 * Author:@author ziyou
 * Date:2022-10-08 21:33
 * Desc:无
 */
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;

/**
 *
 * Function:
 * Author:@author ziyou
 * Date:2022-10-08 21:33
 * Desc:无
 */
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);
  }
}

第三步

创建配置文件,我们接着在 resources 目录下创建一个名为 META-INF/services 的文件夹,在其中创建一个名为 com.example.demo.spi.Compresser 的文件,其中的内容如下:

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

注意该文件的名称必须是接口的全路径,文件里面的内容每一行都是一个实现类的全路径,多个实现类就写在多行里面,效果如下。

Java 中经常被提到的 SPI 到底是什么?

第四步

有了上面的接口,实现类和配置文件,接下来我们就可以使用 ServiceLoader 动态加载实现类,来实现 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 compressers = ServiceLoader.load(Compresser.class);
    for (Compresser compresser : compressers) {
      System.out.println(compresser.getClass());
    }
  }
}

运行的结果如下

Java 中经常被提到的 SPI 到底是什么?

可以看到我们正常的获取到了接口的实现类,并且可以直接使用实现类的解压缩方法。

原理

知道了如何使用 SPI 接下来我们来研究一下是如何实现的,通过上面的测试我们可以看到,核心的逻辑是 ServiceLoader.load() 方法,这个方法有点类似于 Spring 中的根据接口获取所有实现类一样。

点开 ServiceLoader 我们可以看到有一个常量 PREFIX,如下所示,这也是为什么我们必须在这个路径下面创建配置文件,因为 JDK 代码里面会从这个路径里面去读取我们的文件。

Java 中经常被提到的 SPI 到底是什么?

同时又因为在读取文件的时候使用了 class 的路径名称,因为我们使用 load 方法的时候只会传递一个 class,所以我们的文件名也必须是接口的全路径。

Java 中经常被提到的 SPI 到底是什么?

通过 load 方法我们可以看到底层构造了一个 java.util.ServiceLoader.LazyIterator 迭代器。

Java 中经常被提到的 SPI 到底是什么?

在迭代器中的 parse 方法中,就获取了配置文件中的实现类名称集合,然后在通过反射创建出具体的实现类对象存放到 LinkedHashMap<string,s> providers = new LinkedHashMap<>();</string,s> 中。

Java 中经常被提到的 SPI 到底是什么?

常用的框架

SPI 技术的使用非常广泛,比如在 dubbo,不过 dubbo 中的 SPI 有经过改造的,还有我们很常见的数据库的驱动中也使用了 SPI,感兴趣的小伙伴可以去翻翻看,还有 SLF4J 用来加载不同提供商的日志实现类以及 Spring 框架等。

优缺点

前面介绍了 SPI 的原理和使用,那 SPI 有什么优缺点呢?

优点

优点当然是解耦,服务方只要定义好接口规范就好了,具体的实现可以由不同的 Jar 进行实现,只要按照规范实现功能就可以被直接拿来使用,在某些场合会被进行热插拔使用,实现了解耦的功能。

缺点

一个很明显的缺点那就是做不到按需加载,通过源码我们看到了是会将所有的实现类都进行创建的,这种做法会降低性能,如果某些实现类实现很耗时了话将影响加载时间。同时实现类的命名也没有规范,让使用者不方便引用。

总结

阿粉今天给大家介绍了一个 SPI 的原理和实现,感兴趣的小伙伴可以自己去尝试一下,多动手有利于加深记忆哦,如果觉得我们的文章有帮助,欢迎点赞评论分享转发,让更多的人看到。

Java 中经常被提到的 SPI 到底是什么?
更多优质内容欢迎关注公众号【Java 极客技术】,我准备了一份面试资料,回复【bbbb07】免费领取。希望能在这寒冷的日子里,帮助到大家。

Original: https://www.cnblogs.com/zi-you/p/16942914.html
Author: zi-you
Title: Java 中经常被提到的 SPI 到底是什么?

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/797431/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 二项分布近似成泊松分布、正态分布

    多次听到二项分布与泊松分布、正态分布的近似关系,决定写一个博客总结一下。 二项分布 B ( n , p ) \mathrm{B}(n,p)B (n ,p ),有两个参数,n n n…

    Python 2023年8月23日
    041
  • 【Pandas库】(4) 索引操作–重新生成索引

    各位同学好,今天和大家分享一下pandas库的索引操作–重新生成索引。 本文主要介绍如何重新生成 Series类型和 DataFrame类型的索引。 (1)Series…

    Python 2023年8月20日
    078
  • 测试之Pytest

    Pytest 属于单元测试框架。针对软件最小单位(函数、方法)进行正确性的检查测试。框架用途:1.测试发现:从多个文件去找测试用例。2.测试执行:按照一定的顺序和规则执行,并生成结…

    Python 2023年9月14日
    068
  • CSS宝典④-CSS布局秘籍(1)任督二脉BFC/IFC

    HTML系列: 人人都懂的HTML基础知识-HTML教程 HTML元素大全(1) HTML元素大全(2)-表单 CSS系列: CSS基础知识筑基 常用CSS样式属性 CSS选择器大…

    Python 2023年10月16日
    048
  • python 常见文件读取

    txt 文件读取 read 将整篇文章读成一个strreadline方法是每次读取的是文件的一行内容,并且方法的返回值为str字符串类型 ③ readlines方法读取的是整个文件…

    Python 2023年8月7日
    067
  • 【Anaconda】安装源—豆瓣,清华

    豆瓣源 pip install -i https://pypi.douban.com/simple/ PackageName 清华源 pip install -i https://…

    Python 2023年6月3日
    049
  • 一、PyQtgraph简介

    目录 1.什么是PyQtgraph 2.pyqtgraph 的核心功能包括: 3.为什么选择PyQtgraph 4.命名约定 5.效果赏析 1.什么是PyQtgraph PyQtG…

    Python 2023年9月5日
    052
  • python进行敏感性分析(SALib库)

    什么是敏感性分析 敏感性分析(sensitivity analysis)是指从定量分析的角度研究有关因素发生某种变化对某一个或一组关键指标影响程度的一种不确定分析技术。每个输入的灵…

    Python 2023年8月24日
    076
  • 一些常用的python绘图包

    文章目录 matplotlib * 点线 散点 样式 坐标系 数学之心 等高线 热力图 饼图 分图显示 scatter 3D wireframe 3D surface 3D con…

    Python 2023年9月2日
    043
  • Cartopy画地图第八天(冷空气南下,NCL色标使用)

    Cartopy画地图第八天(冷空气南下,NCL色标使用) 相信很多朋友都看过这张漂亮的图吧这是中国气象爱好者公众号画的一张反映冷空气的图片,当时就被惊艳到了,本帖就来复刻一下这张图…

    Python 2023年9月3日
    050
  • PyCharm——调用matplotlib绘图时图像弹出问题

    要在PyCharm 中使用Matplotlib 绘图 并将结果展示在网页中,可以按照以下步骤进行操作: 1. 导入Matplotlib 库并设置绘图 风格。在代码文件开头添加如下代…

    Python 2023年9月1日
    043
  • NLP新手入门指南|北大-TANGENT

    开源的学习资源:《NLP 新手入门指南》,项目作者为北京大学 TANGENT 实验室成员。 该指南主要提供了 NLP 学习入门引导、常见任务的开发实现、各大技术教程与文献的相关推荐…

    Python 2023年10月21日
    053
  • Pandas的基本属性和操作(增,删,改,查,合并)

    官方文档 Pandas官网 基本属性 显示详细 `pythonimport pandas as pdd1 = pd.DataFrame({ “姓名”: [&…

    Python 2023年8月9日
    047
  • python游戏开发必有套路

    游戏开发很简单,只需几个步骤 重点: 控制和显示窗口: pygame.display.方法 必有步骤1:创建游戏窗口 初始化游戏窗口 pygame.init() 设置游戏窗口 必用…

    Python 2023年9月18日
    030
  • 使用 Qt for Android 获取并利用手机传感器数据(上篇)开发环境省心搭建

    现代手机拥有许多传感器,包括地磁、姿态、GPS、光照、温度、气压、摄像、声音、电磁等,完全就是一个高度集成的科学仪器。不夸张的说,一部手机加上一个外围的计算机和控制系统,做一个功能…

    Python 2023年11月9日
    093
  • Python基础入门第一课

    一:python概念 python2.0和python3.0是不兼容的,目前主流是python3.0 二:python的优点和缺点 优点:1.简单,易学。2.免费,开源 开发者可以…

    Python 2023年8月11日
    041
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球