java中SPI(服务提供者的接口)

news/2024/12/22 15:13:08/

java中SPI(服务提供者的接口)

    • 一:什么是SPI
    • 二:java SPI示例
      • 1.SPI服务提供方
      • 2.SPI服务应用方开发者
    • 三:JavaSPI 机制的核心-ServiceLoader

一:什么是SPI

SPI:“服务提供者的接口”,是一种服务发现机制

用于实现框架或库的扩展点,允许在运行时动态地插入或更换组件实现。

它提供了一个框架(JDK1.6后ServiceLoader)来发现和加载服务实现,使得软件模块能够灵活地选择和使用不同的服务提供商。

在这里插入图片描述

java中通俗讲就是:

  • 对框架或第三方jar包提供者来说可制定规范,提供给开发者可扩展性
  • 对开发者来说可以根据需要轻松替换框架或第三方jar包中提供了SPI机制的接口的实现

java_SPI_15">二:java SPI示例

1.SPI服务提供方

SPI服务提供方架构图:
在这里插入图片描述
定义接口规范:

java">public interface SpiService {/*** 呼叫方式*/void call();
}

加载具体的服务实现:

java">package com.lmy.config;import com.lmy.service.SpiService;import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;/*** @author : lmy* @date : 2024/9/14 上午 11:35* 加载具体的服务实现*/
public class SpiServiceLoader {private static volatile SpiServiceLoader LOADER;private final SpiService spiService;private final List<SpiService> spiServiceList;/*** 加载服务* */private SpiServiceLoader() {ServiceLoader<SpiService> loader = ServiceLoader.load(SpiService.class);List<SpiService> list = new ArrayList<>();for (SpiService spiService : loader) {list.add(spiService);}spiServiceList = list;if (!list.isEmpty()) {// 取第一个spiService = list.get(0);} else {spiService = null;}}/*** SpiServiceLoader 单例加载* */public static SpiServiceLoader getLOADER() {if (LOADER == null) {synchronized (SpiServiceLoader.class) {if (LOADER == null) {LOADER = new SpiServiceLoader();}}}return LOADER;}public void call(){if(spiServiceList.isEmpty()){System.out.println("SpiService服务未加载!");}else {SpiService spiService = spiServiceList.get(0);spiService.call();}}}

默认实现:

java">package com.lmy.service.impl;import com.lmy.service.SpiService;/*** @author : lmy* @date : 2024/9/14 上午 10:58* 默认实现*/
public class SpiServiceImpl implements SpiService {@Overridepublic void call() {System.out.println("默认手机呼叫");}
}

指定服务实现方式:
须在resource下创建META-INF.services,文件名为接口全限定类名,配置为需要被加载的接口实现类的全限定类名
在这里插入图片描述

com.lmy.service.impl.SpiServiceImpl

项目打包发布本地:
在这里插入图片描述

2.SPI服务应用方开发者

开发者引入jar包使用服务:

java"><dependency><groupId>com.lmy</groupId><artifactId>SPI-interface</artifactId><version>1.0-SNAPSHOT</version>
</dependency>
java">package com.lmy.Spi;import com.lmy.config.SpiServiceLoader;
import org.junit.Test;/*** @author : lmy* @date : 2024/9/14 上午 11:48*/
public class SpiTest {@Testpublic void spiTest () {SpiServiceLoader loader = SpiServiceLoader.getLOADER();loader.call();}
}

执行结果:
在这里插入图片描述
开发者根据需要扩展替换为自己的服务实现:

java">package com.lmy.Spi.service;import com.lmy.service.SpiService;/*** @author : lmy* @date : 2024/9/14 下午 2:09*/
public class SpiServiceNewImpl implements SpiService {@Overridepublic void call() {System.out.println("卫星直呼");}
}

在这里插入图片描述

com.lmy.Spi.service.SpiServiceNewImpl

执行结果:
在这里插入图片描述

三:JavaSPI 机制的核心-ServiceLoader

上面代码可见是通过ServiceLoader 去加载具体的服务实现的
在这里插入图片描述
ServiceLoader 是从JDK1.6 开始提供的一个类,用于加载服务提供者。

进入源码可见:
其中 String PREFIX = “META-INF/services/”;
这个就是JDK的SPI功能规定的具体服务实现的配置信息文件所在的目录 META-INF/services/
在这里插入图片描述
JDK的SPI规定 服务实现者需要在 META-INF/services/ 目录下 新建文件名为 SPI接口全限定类名的文件
文件内容为 服务实现者需要被加载的具体类的全限定类名

具体源码底层实现参考:https://blog.csdn.net/qq_37883866/article/details/139000021 中第3点


http://www.ppmy.cn/news/1527236.html

相关文章

mysql数据库如何开启binlog日志

首先我们要知道什么是binlog日志 binlog是 MySQL数据库的二进制日志文件&#xff0c;记录了数据库更改的所有操作&#xff0c;但不包括SELECT和SHOW这类操作&#xff0c;这些操作对数据进行修改、管理操作、数据库修改等操作都会被记录在日志中。 对于一个sql&#xff0c;它…

通过adb命令打开手机usb调试

adb shell settings put global adb_enabled 1 这个命令会将全局ADB启用设置为1&#xff0c;允许通过ADB进行调试。 adb shell settings put secure adb_authentication_enabled 1 这个命令会启用ADB身份验证&#xff0c;允许设备在连接时要求授权。 adb shell settings put …

BSN六周年:迈向下一代互联网

当前&#xff0c;分布式技术作为现代计算机科学和信息技术的重要组成部分&#xff0c;在云计算、区块链等技术的推动下&#xff0c;正以多样化的形式蓬勃发展。 ​而区块链作为一种特殊的分布式系统&#xff0c;近年来也在各个领域得到了广泛关注。通过在区块链上运行智能合约…

JDBC笔记

文章目录 准备MySQL数据的建立和建表 idea 建工程和模块设置属性配置文件编写JDBC代码URL的设置JDBC 代码配置文件 准备MySQL 数据的建立和建表 idea 建工程和模块 设置属性配置文件 编写JDBC代码 URL的设置 JDBC 代码 package com.yanyu;import java.sql.*; import java.util…

神经网络的公式推导与代码实现(论文复现)

神经网络的公式推导与代码实现&#xff08;论文复现&#xff09; 本文所涉及所有资源均在传知代码平台可获取 概述 本文将详细推导一个简单的神经网络模型的正向传播、反向传播、参数更新等过程&#xff0c;并将通过一个手写数字识别的例子&#xff0c;使用python手写和pytorch…

使用vant UI实现时间段选择

需求&#xff1a;选择时间段或者选择日期&#xff0c;时间段不允许跨月&#xff0c;选完开始时间后&#xff0c;结束时间可选 “开始日期~当月最后一天” 格式&#xff1a;2023-01-01~2023-01-23 或者 2023-01-01 这里使用vantUI 示例代码: <van-fieldlabel"日期&quo…

(CS231n课程笔记)深度学习之损失函数详解(SVM loss,Softmax,熵,交叉熵,KL散度)

学完了线性分类&#xff0c;我们要开始对预测结果进行评估&#xff0c;进而优化权重w&#xff0c;提高预测精度&#xff0c;这就要用到损失函数。 损失函数&#xff08;Loss Function&#xff09;是机器学习模型中的一个关键概念&#xff0c;用于衡量模型的预测结果与真实标签…

openCV的python频率域滤波

在OpenCV中实现频率域滤波通常涉及到傅里叶变换(Fourier Transform)和其逆变换(Inverse Fourier Transform)。傅里叶变换是一种将图像从空间域转换到频率域的数学工具,这使得我们可以更容易地在图像的频域内进行操作,如高通滤波、低通滤波等。 下面,我将提供一个使用Py…