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

news/2024/9/19 17:42:50/ 标签: java

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…

linux-L3-linux 复制文件

linux 中要将文件file1.txt复制到目录dir中&#xff0c;可以使用以下命令 cp file1.txt dir/复制文件 cp /path/to/source/file /path/to/destination移动 mv /path/to/source/file /path/to/destination复制文件夹内的文件 cp -a /path/to/source/file /path/to/destinati…

Rust的常量

【图书介绍】《Rust编程与项目实战》-CSDN博客 《Rust编程与项目实战》(朱文伟&#xff0c;李建英)【摘要 书评 试读】- 京东图书 (jd.com) Rust编程与项目实战_夏天又到了的博客-CSDN博客 3.3.1 常量的定义 常量和变量是高级程序设计语言中数据的两种表现形式。这里我们先…

Go语言并发编程之select语句详解

在Go语言的并发模型中,channel是用于在goroutine之间进行通信的主要工具,而select语句则是将多个channel结合在一起的关键机制。通过select语句,开发者可以同时监控多个channel的状态,从而构建更为复杂和灵活的并发逻辑。本文将详细介绍select语句的原理和用法,并通过多个…

62. 圆圈中最后剩下的数字

comments: true difficulty: 简单 edit_url: https://github.com/doocs/leetcode/edit/main/lcof/%E9%9D%A2%E8%AF%95%E9%A2%9862.%20%E5%9C%86%E5%9C%88%E4%B8%AD%E6%9C%80%E5%90%8E%E5%89%A9%E4%B8%8B%E7%9A%84%E6%95%B0%E5%AD%97/README.md 面试题 62. 圆圈中最后剩下的数字…

硬件工程师笔试面试学习汇总——器件篇目录

目录 一、器件篇目录 1、电阻(Resistors) 1.1、 基础 1.2、相关问题 1.3、上拉电阻 1.4、下拉电阻 2、电容(Capacitors) 2.1、基础 2.2、相关问题 3、电感(Inductors) 3.1、基础 3.2、相关问题 4、二极管(Diodes) 4.1、基础 4.2、相关问题 5、三极管 5.1…

PostgreSQL的walsender和walreceiver进程介绍

PostgreSQL的walsender和walreceiver进程介绍 在 PostgreSQL 中&#xff0c;WAL (Write-Ahead Logging) 是一种用于确保数据库事务日志安全可靠的机制。WAL 是 PostgreSQL 进行数据库恢复、复制等操作的基础。walsender 和 walreceiver 是 PostgreSQL 内部两个非常重要的进程&…

unity UnityWebRequest 的request.downloadHandler 空应用

unity UnityWebRequest 的request.downloadHandler 空应用 private IEnumerator Test_Get() {UnityWebRequest request new UnityWebRequest(tmp_getURL, "GET");yield return request.SendWebRequest();if (request.result UnityWebRequest.Result.ConnectionErr…

用于稀疏自适应深度细化的掩码空间传播网络 CVPR2024

目录 Masked Spatial Propagation Network for Sparsity-Adaptive Depth Refinement &#xff08;CVPR 2024&#xff09;用于稀疏自适应深度细化的掩码空间传播网络1 介绍2 算法流程2.1 问题建模2.2 Guidance Network2.3 MSPN 模块 3 实验结果3.1 稀疏度自适应深度细化对比试验…

基于微信小程序的图书馆预约占座系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 基于微信小程序JavaSpringBootVueMySQL的图…

目标检测基本知识

目标检测 一、目标检测二、常用的评价指标2.1 IOU2.2 NMS(非极大值抑制) 三、R-CNN网络基础3.1 Overfeat模型3.2 RCNN模型3.3FastRCNN模型 四、Faster-RCNN网络4.1 网络工作流程 五、yolo系列5.1 yoloV3 六、SSD算法 一、目标检测 目标检测的任务是找出图像中所有感兴趣的目标…

Java项目实战II基于Java+Spring Boot+MySQL的图书管理系统的设计与实现 (源码+数据库+文档)

目录 一、前言 二、技术介绍 三、系统实现 四、论文参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 在信息爆炸…

C++:初始化列表

构造函数在上一篇帖子我们提到了对成员变量初始化的功能&#xff0c;出了在构造函数的函数体中队成员变量一个一个赋值以外&#xff0c;我们还可以采用初始化列表。 #include<iostream> using namespace std;class AA { private:int a;const int b; public:AA():b(200),…