你知道SPI的原理以及实现?

1、什么是SPI?

SPI(Service Provider Interface),是JDK内置的一种服务提供发现机制,可以用来启用框架扩展和替换组件,主要是被框架的开发人员使用,比如 java.sql.Driver 接口,其他不同厂商可以针对同一接口做出不同的实现,MySQL 和 PostgreSQL 都有不同的实现提供给用户,而Java的SPI机制可以为某个接口寻找服务实现。Java中SPI机制主要思想是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要,其核心思想就是解耦
Java SPI 实际上是“基于接口的编程+策略模式+配置文件”组合实现的动态加载机制。
SPI与API区别:

  • API是调用并用于实现目标的类、接口、方法等的描述;
  • SPI是扩展和实现以实现目标的类、接口、方法等的描述;

换句话说,API 为操作提供特定的类、方法,SPI 通过操作来符合特定的类、方法。
当服务的提供者提供了一种接口的实现之后,需要在classpath下的META-INF/services/目录里创建一个以服务接口命名的文件,这个文件里的内容就是这个接口的具体的实现类。当其他的程序需要这个服务的时候,就可以通过查找这个jar包(一般都是以jar包做依赖)的META-INF/services/中的配置文件,配置文件中有接口的具体实现类名,可以根据这个类名进行加载实例化,就可以使用该服务了。JDK中查找服务的实现的工具类是:java.util.ServiceLoader。
面向的对象的设计里,我们一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。一旦代码里涉及具体的实现类,就违反了可拔插的原则,如果需要替换一种实现,就需要修改代码。
为了实现在模块装配的时候不用在程序里动态指明,这就需要一种服务发现机制。java spi就是提供这样的一个机制:为某个接口寻找服务实现的机制。这有点类似IOC的思想,将装配的控制权移到了程序之外。

2、使用场景

概括地说,适用于:调用者根据实际使用需要,启用、扩展、或者替换框架的实现策略
比较常见的例子:

  • 数据库驱动加载接口实现类的加载 => JDBC加载不同类型数据库的驱动
  • 日志门面接口实现类加载 => SLF4J加载不同提供商的日志实现类
  • Spring => Spring中大量使用了SPI,比如:对servlet3.0规范对ServletContainerInitializer的实现、自动类型转换Type Conversion SPI(Converter SPI、Formatter SPI)等
  • Dubbo => Dubbo中也大量使用SPI的方式实现框架的扩展, 不过它对Java提供的原生SPI做了封装,允许用户扩展实现Filter接口

3、SPI的优缺点

优点

使用Java SPI机制的优势是实现解耦,使得第三方服务模块的装配控制的逻辑与调用者的业务代码分离,而不是耦合在一起。应用程序可以根据实际业务情况启用框架扩展或替换框架组件
相比使用提供接口jar包,供第三方服务模块实现接口的方式,SPI的方式使得源框架,不必关心接口的实现类的路径,可以不用通过下面的方式获取接口实现类:

  • 代码硬编码import 导入实现类
  • 指定类全路径反射获取:例如在JDBC4.0之前,JDBC中获取数据库驱动类需要通过Class.forName(“com.mysql.jdbc.Driver”),类似语句先动态加载数据库相关的驱动,然后再进行获取连接等的操作
  • 第三方服务模块把接口实现类实例注册到指定地方,源框架从该处访问实例

通过SPI的方式,第三方服务模块实现接口后,在第三方的项目代码的META-INF/services目录下的配置文件指定实现类的全路径名,源码框架即可找到实现类

缺点

  • 虽然ServiceLoader也算是使用的延迟加载,但是基本只能通过遍历全部获取,也就是接口的实现类全部加载并实例化一遍。如果你并不想用某些实现类,它也被加载并实例化了,这就造成了浪费。获取某个实现类的方式不够灵活,只能通过Iterator形式获取,不能根据某个参数来获取对应的实现类。
  • 多个并发多线程使用ServiceLoader类的实例是不安全的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/21215.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【conda】解决conda activate无效的问题

conda activate 虚拟环境名字执行上述命令失效,提示如下信息: 经查询,原因是新版的 conda 不再使用 activate 来激活虚拟环境,而是改用: source activate 虚拟环境名退出虚拟环境还是: conda deactivate…

sqlite基本操作

简介 文章目录 简介1.数据库的安装2.数据库命令:API,创建表单代码 csprintf()getchar和scanf() 1.数据库的安装 sudo dpkg -i *.deb这个报错表明出现依赖问题 用这个命令后再试试sudo apt --fix-broken in…

Apache来源于北美印第安部落?

Apache HTTP服务器,通常简称为Apache,是一个由Apache软件基金会(Apache Software Foundation,简称ASF)维护的开源网页服务器软件。以下是Apache的前世今生的概述: 起源: Apache的起源可以追溯…

计算机组成原理----浮点数的表示和运算

目录 一.浮点数的表示 1.浮点数的作用和基本原理 2.浮点数的规格化 3.浮点数的表示范围 二.IEEE 754标准 三.浮点数的加减运算 1.加减运算 2.强制类型转换 一.浮点数的表示 1.浮点数的作用和基本原理 定点数在字节数固定的情况下,能表示的数字是很有限的&…

输入15个整数,计算并输出15个整数的和,并输出其中最大值和最小值;

输入15个整数&#xff0c;计算并输出15个整数的和&#xff0c;并输出其中最大值和最小值&#xff1b; #include<stdio.h> int main() {int i0,s0,max,min,jg0,jp0,og0,omax; int a[15]{12,13,14,16,17,18,19,10,1,2,3,4,5,6,7}; maxa[0],mina[0]; for(i0,s0;i<15;i) …

Android编程用什么语言:深入探索与开发实践

Android编程用什么语言&#xff1a;深入探索与开发实践 在移动应用开发的浩瀚海洋中&#xff0c;Android平台无疑占据了重要的地位。而对于那些渴望投身于此领域的开发者们来说&#xff0c;选择何种编程语言进行Android编程&#xff0c;无疑是一个关键且充满困惑的问题。本文将…

BIT 2024 编译原理 Lab. 4 四代编译器实验说明和要求

实验四&#xff1a;四代编译器实验 一、实验要求 详细实验要求请参考文件《Lab4实验说明和要求.pdf》。 二、实验思路 1、与 lab3 的对比 如果你在 lab3 就已经像我一样单独写了个函数处理表达式&#xff0c;那么理论上&#xff0c;lab4 相比于 lab3&#xff0c;不过就是多…

ComfyUi安装OOTDiffusion插件的diffusers版本问题

OOTDiffusion换装 在github上有近5K的star了&#xff08;https://github.com/levihsu/OOTDiffusion&#xff09;。 diffusers版本问题 最新版是0.27.2&#xff0c;不能低于0.25&#xff0c;但是OOT换装需要0.24&#xff0c;否则会报错&#xff1a; ComfyUI\custom_nodes\Comf…

系统架构设计师【第14章】: 云原生架构设计理论与实践 (核心总结)

文章目录 14.1 云原生架构产生背景14.2 云原生架构内涵14.2.1 云原生架构定义14.2.2 云原生架构原则14.2.3 主要架构模式14.2.4 典型的云原生架构反模式 14.3 云原生架构相关技术14.3.1 容器技术14.3.2 云原生微服务14.3.3 无服务器技术14.3.4 服务网格 14.4 云原生…

HTML+CSS 文本动画卡片

效果演示 实现了一个图片叠加文本动画效果的卡片&#xff08;Card&#xff09;布局。当鼠标悬停在卡片上时&#xff0c;卡片上的图片会变为半透明&#xff0c;同时显示隐藏在图片上的文本内容&#xff0c;并且文本内容有一个从左到右的渐显动画效果&#xff0c;伴随着一个白色渐…

Python命令行参数处理:详解argparse模块

Python命令行参数处理&#xff1a;详解argparse模块 在Python开发中&#xff0c;能够处理命令行参数是一项非常实用的技能。argparse模块是Python标准库中用于解析命令行参数的模块&#xff0c;它能够轻松地处理复杂的命令行接口。本文将详细介绍如何使用argparse模块来处理命…

YOLOV10训练自己的数据集

*************************************************** 码字不易&#xff0c;收藏之余&#xff0c;别忘了给我点个赞吧&#xff01; *************************************************** Start YOLOV10训练自己的数据集 官方论文&#xff1a;https://arxiv.org/abs/2405…

使用busybox快速创建rootfs系统(硬件:atk-dl6y2c)

目录 概述 1 编译busybox 1.1 配置Makefile 1.2 需改参数 1.3 配置busybox 1.4 编译busybox 2 完善 rootfs下文件 2.1 rootfs 的“/lib”目录添加库文件 2.2 rootfs 的“usr/lib”目录添加库文件 2.3 创建其他目录 3 完善其他文件 3.1 完善etc/init.d/rcS 3.2 完善…

Golang | Leetcode Golang题解之第128题最长连续序列

题目&#xff1a; 题解&#xff1a; func longestConsecutive(nums []int) int {numSet : map[int]bool{}for _, num : range nums {numSet[num] true}longestStreak : 0for num : range numSet {if !numSet[num-1] {currentNum : numcurrentStreak : 1for numSet[currentNum…

【CMake】CMake入门(五)打包安装程序 使用CMake管理库 打包调试版和发行版

本篇文章不是新手入门教学文章&#xff0c;主要是记录笔者个人的学习笔记 CMake入门&#xff08;五&#xff09; 一、打包二、使用CMake管理库三、打包调试版和发行版 一、打包 发布程序可以有多种形式&#xff0c;比如安装包、压缩包、源文件等。CMake也提供了打包程序cpack可…

YOLOv8训练自定义项目

训练内容&#xff1a;基于yolo的筒纱实例分割 数据设置&#xff1a; 1&#xff09;https://ultralytics.com/assets/coco8-seg.zip&#xff0c;下载coco8-seg.zip&#xff0c;解压&#xff0c;记住各个文件夹内的文件名&#xff08;12为为长度&#xff0c;如000000000001.jpg…

8、架构-分布式的共识

概述 在正式探讨分布式环境中面临的各种技术问题和解决方案前&#xff0c;我 们先把目光从工业界转到学术界&#xff0c;学习几种具有代表性的分布式共识 算法&#xff0c;为后续在分布式环境中操作共享数据准备好理论基础。下面笔 者从一个最浅显的场景开始&#xff0c;引出本…

金钱的认知,你如何理解呢?

金钱的认知 建立在金钱之上的爱情是纯真的爱&#xff0c;朋友关系也才够纯粹&#xff0c;才是单纯的世界&#xff0c;反之没了钱的条件爱情和友情的美好关系极易破碎&#xff0c;也极易反目成仇。 心若美好钱就美好&#xff0c;心有欲望狰狞钱就是只咬人的老虎&#xff0c;钱…

python练习五

Title1&#xff1a;请实现一个装饰器&#xff0c;每次调用函数时&#xff0c;将函数名字以及调用此函数的时间点写入文件中 代码&#xff1a; import time time time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) # 获取当前的时间戳 # 定义一个有参装饰器来实…

Linux 僵尸进程和孤儿进程

一.Z(zombie)-僵尸进程 1.僵死状态&#xff08;Zombies&#xff09;是一个比较特殊的状态。当进程退出并且父进程&#xff08;使用wait()系统调用后&#xff09;没有读取到子进程退出的返回代码时就会产生僵死(尸)进程 2.僵死进程会以终止状态保持在进程表中&#xff0c;并且会…