什么是 SPI,和API有什么区别?
面试回答
Java 中区分 API 和 SPI,通俗的讲:API 和 SPI 都是相对的概念,他们的差别只在语义上,API 直接被应用开发人员使用,SPI 被框架扩展人员使用。
API Application Programming Interface
大多数情况下,都是实现方来制定接口并完成对接口的不同实现,调用方仅仅依赖却无权选择不同实现。
SPI Service Provider Interface
而如果是调用方来制定接口,实现方来针对接口实现不同的实现。调用方来选择自己需要的实现方。
知识扩展
如何定义一个 SPI
步骤1、定义一组接口(假设是 com.chiyi.test.IShout),并写出接口的一个或多个实现,(假设是 com.chiyi.test.Dog、com.chiyi.test.Cat)。
public interface IShout {void shout();
}
public class Dog implements IShout{@Overridepublic void shout() {System.out.println("wang wang");}
}
public class Cat implements IShout{@Overridepublic void shout() {System.out.println("miao miao");}
}
步骤2、在 src/main/resources/ 下建立 /META-INF/services目录,新增一个以接口命名的文件(com.chiyi.test.IShout 文件),内容是要应用的实现类(这里是 com.chiyi.test.Dog和com.chiyi.test.Cat,每行一个类)。
com.chiyi.test.Dog
com.chiyi.test.Cat
步骤3、使用 ServiceLoader 来加载配置文件中指定的实现。
public class Main {public static void main(String[] args) {ServiceLoader<IShout> shouts=ServiceLoader.load(IShout.class);for(IShout s:shouts){s.shout();}}
}
代码输出:
wang wang
miao miao
SPI 的实现原理
看 ServiceLoader 类的签名类的成员变量:
public final class ServiceLoader<S>implements Iterable<S>
{private static final String PREFIX = "META-INF/services/";// 代表被加载的类或者接口private final Class<S> service;// 用于定位,加载和实例化 providers 的类加载器private final ClassLoader loader;// 创建 ServiceLoader 时采用的访问控制上下文private final AccessControlContext acc;// 缓存 providers,按实例化的顺序排列private LinkedHashMap<String,S> providers = new LinkedHashMap<>();// 懒查找迭代器private LazyIterator lookupIterator;······
}
参考具体源码,梳理了一下,实现的流程如下:
- 应用程序调用
ServiceLoader.load方法,ServiceLoader.load方法内先创建一个新的ServiceLoader,并实例化该类中的成员变量,包括:
-
- loader(ClassLoader 类型,类加载器)
- acc(AccessControlContext 类型,访问控制器)
- providers(LinkedHashMap 类型,用于缓存加载成功的类)
- lookupIterator(实现迭代器功能)
- 应用程序通过迭代器接口获取对象实例
-
- ServiceLoader 先判断成员变量 providers 对象中(LinkedHashMap 类型)是否有缓存实例对象,如果有缓存,直接返回。
- 如果没有缓存,执行类的装载:
-
-
- 读取 META-INF/services/ 下的配置文件,获得所有能被实例化的类的名称
- 通过反射方法 Class.forName() 加载类对象,并用 instance() 方法将类实例化
- 把实例化的类缓存到 providers 对象中(LinkedHashMap 类型)
- 然后返回实例对象
-
SPI 的应用场景
概括地说,适用于:调用者根据实际使用需要,启用、扩展、或者替换框架的实现策略。
比如常见的例子:
- 数据库驱动加载接口实现类的加载
- JDBC 加载不同类型数据库的驱动
- 日志门面接口实现类加载
- SLF4J 加载不同提供商的日志实现类
Spring
Spring 中大量使用了 SPI,比如:对 servlet3.0 规范对 ServletContainerInitializer 的实现、自动类型转换 Type Conversion SPI(Converter SPI、Formatter SPI)等
Dubbo
Dubbo 中也大量使用 SPI的方式实现框架的扩展,不过它对 java 提供的原生 SPI 做了封装,允许用户扩展实现 Filter 接口。
相关文章:
什么是 SPI,和API有什么区别?
面试回答 Java 中区分 API 和 SPI,通俗的讲:API 和 SPI 都是相对的概念,他们的差别只在语义上,API 直接被应用开发人员使用,SPI 被框架扩展人员使用。 API Application Programming Interface 大多数情况下ÿ…...
python3 安装clickhouse_sqlalchemy(greenlet) 失败
环境信息: centos7操作系统,python3.8 执行pip3 install clickhouse_sqlalchemy或者pip3 install greenlet报以下报错: Command "/opt/python3.6.10-customized/bin/python3.6 -u -c "import setuptools, tokenize;file/tmp/pip-in…...
五款拿来就能用的炫酷表白代码
「作者主页」:士别三日wyx 「作者简介」:CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」:小白零基础《Python入门到精通》 五款炫酷表白代码 1、无限弹窗表白2、做我女朋友好吗,不同意就关机3、…...
Springboot 封装整活 Mybatis 动态查询条件SQL自动组装拼接
前言 ps:最近在参与3100保卫战,战况很激烈,刚刚打完仗,来更新一下之前写了一半的博客。 该篇针对日常写查询的时候,那些动态条件sql 做个简单的封装,自动生成(抛砖引玉,搞个小玩具&a…...
宝塔部署Java+Vue前后端分离项目经验总结
前言 之前部署服务器都是在Linux环境下自己一点一点安装软件,听说用宝塔傻瓜式部署更快,这次浅浅尝试了一把。 确实简单! 1、 买服务器 咋买服务器略,记得服务器装系统就装 Cent OS 7系列即可,我装的7.6。 2、创建…...
【公告】停止更新
CSDN 博客的限制太多了。阅读体验也非常差。后续将不再 CSDN 上更新。 逐步迁移到掘金和个人博客。 欢迎关注 掘金:0xforee 个人博客:0xforee’s blog...
AutoHotKey+VSCode开发扩展推荐
原来一直用的大众推荐的SciTeAHK版,最近发现VSCode更舒服一些,有几个必装的扩展推荐一下: AutoHotkey Plus 请注意不是AutoHotkey Plus Plus。如果在扩展商店里搜索会有两个,一个是Plus,一个是Plus Plus。我选择Pllus&…...
了解 JSON 格式
一、JSON 基础 JSON(JavaScript Object Notation,JavaScript 对象表示法)是一种轻量级的数据交换格式,JSON 的设计目的是使得数据的存储和交换变得简单。 JSON 易于人的阅读和书写,同时也易于机器的解析和生成。尽管 J…...
[RDMA] 高性能异步的消息传递和RPC :Accelio
1. Introduce Accelio是一个高性能异步的可靠消息传递和RPC库,能优化硬件加速。 RDMA和TCP / IP传输被实现,并且其他的传输也能被实现,如共享存储器可以利用这个高效和方便的API的优点。Accelio 是 Mellanox 公司的RDMA中间件,用…...
typescript报错:‘name‘ was also declared here
问题再现 用 Typescript 时, 遇到一个声明常量 name 的报错。代码如下: let name:string"zhangsan"; let num:number1001;执行编译时报错: 原因 在默认状态下,typescript 将 DOM typings 作为全局的运行环境&#…...
第十章:联邦学习视觉案例
代码 传送门...
c语言——输出一个整数的所有因数
//输出一个整数的所有因数 #include<stdio.h> #include<stdlib.h> int main() {int number,i;printf("输入整数:");scanf("%d",&number);printf(" %d 的因数有: ",number);for(i1;i<number;i){if(numb…...
mqtt学习记录
目录 1 匿名登录2 ⽤户名密码登录,配置接收的主题mosquitto 配置文件修改添加⽤户信息添加topic和⽤户的关系登录演示 3 遗嘱机制 1 匿名登录 ⾸先打开三个终端, 启动代理服务:mosquitto -v -v 详细模式 打印调试信息 默认占⽤:…...
爬虫逆向实战(十八)--某得科技登录
一、数据接口分析 主页地址:某得科技 1、抓包 通过抓包可以发现数据接口是AjaxLogin 2、判断是否有加密参数 请求参数是否加密? 查看“载荷”模块可以发现有一个password加密参数和一个__RequestVerificationToken 请求头是否加密? 无…...
Java-数组
什么是数组 数组:可以看成是相同类型元素的一个集合。在内存中是一段连续的空间。 在java中, 数组中存放的元素其类型相同数组的空间是连在一起的每个空间有自己的编号,起始位置的编号为0,即数组的下标。 数组的创建及初始化 数…...
Dart 入门Hello world
1、下载Dart sdk IntelliJ & Android Studio | Dart 2、安装Dart 插件 3、安装后重启IDEA,创建Dart项目 4、创建dart文件 5、编写函数: void main() {print("Hello world"); } 6、运行: 官网学习:Dart 语言开发文…...
HTML是什么?
HTML是什么? 超文本标记语言(英语:HyperText Markup Language,简称:HTML)是一种用于创建网页的标准标记语言。 您可以使用 HTML 来建立自己的 WEB 站点,HTML 运行在浏览器上,由浏览器…...
【UniApp开发小程序】商品详情展示+评论、评论展示、评论点赞+商品收藏【后端基于若依管理系统开发】
文章目录 界面效果界面实现工具js页面日期格式化 后端收藏ControllerServicemapper 评论ControllerServiceMapper 商品Controller 阅读Service 界面效果 【说明】 界面中商品的图片来源于闲鱼,若侵权请联系删除 【商品详情】 【评论】 界面实现 工具js 该工…...
rabbitMq安装后无法启动可视化页面http://localhost:15672处理
本次安装环境信息: 系统:win10 64位专业版 erlang:otp_win64_23.0 rabbitMQ:rabbitmq-server-3.8.5 安装rabbitMQ需要依赖erlang语言环境,所以需要我们下载erlang的环境安装程序。 一、下载安装程序 rabbitMQ安装…...
材料行业可以转IC设计后端吗?
近来有许多材料行业的小伙伴通过后台来问我对于职业规划的看法,甚至有些小伙伴直接点明了某个行业适不适合自己,那么我这边仅以近年来比较热门的数字芯片设计来展开讲讲,材料适不适合转行做IC呢。 对于理工科的同学而言,选择哪个…...
深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...
