当前位置: 首页 > news >正文

Java SPI机制详解-01

1. 概述

SPI(Service Provider Interface),是 Java 6 引入了一个内置功能,实现服务提供发现和加载机制,使之与特定接口的匹配。

SPI 机制的核心思想就是 解耦 ,将装配的控制权移到程序之外,这在企业模块化设计中非常重要。

有的人喜欢拿 SPIAPI 之间做比较,关于二者之间的差异主要在于侧重点不一样。

  • API :侧重 调用 并用于实现目标的类、接口、方法等的描述;
  • SPI :侧重对已实现目标类、接口、方法的 扩展和实现

20230808170610

2. 使用场景

调用者根据实际使用需要,启用、扩展、或者替换框架的实现策略。

  • 数据库驱动加载接口实现类的加载: JDBC 加载不同类型数据库的驱动

  • 日志门面接口实现类加载:SLF4J 加载不同提供商的日志实现类

  • Spring 框架:Spring 中大量使用 SPI ,比如:对 Servlet3.0 规范对 ServletContainerInitializer 的实现、自动类型转换 Type Conversion SPI(Converter SPI、Formatter SPI)

3. 入门使用介绍

在实际使用 SPI 需要遵循以下约定:

  • 按照定义创建加载文件:当服务提供者提供了接口的一种具体实现后,在 jar 包的 META-INF/services 目录下创建一个以 接口全限定名为命名的文件,内容为实现类的全限定名;
  • 动态加载:主程序通过 java.util.ServiceLoder 动态装载实现模块,它通过扫描 META-INF/services 目录下的配置文件找到实现类的全限定名,把类加载到 JVM
  • 无参构造方法: SPI实现类必须携带一个不带参数的构造方法;
  • 相同classpath:接口实现类所在的 jar 包放在主程序的 classpath中;

4. 示例

4.1. 构建接口

此处演示作用,只定义一组接口,接口为 灵长类 动物,它包含一个方法, 叫 动作


package io.github.rothschil.spi.framework;/*** 灵长类动物* @author <a href="mailto:WCNGS@QQ.COM">Sam</a>* @version 1.0.0*/
public interface Primate {void action();
}

4.2. 拓展实现

灵长类 这个接口,我们假定它的实现为人类 、猴子,它们都能有属于自己的动物。

  • 人类

package io.github.rothschil.spi.framework.impl;import io.github.rothschil.spi.framework.Primate;public class Human implements Primate {@Overridepublic void action() {System.out.println("Human");}
}
  • 猴子

package io.github.rothschil.spi.framework.impl;import io.github.rothschil.spi.framework.Primate;public class Monkey implements Primate {@Overridepublic void action() {System.out.println("Monkey");}
}

4.3. 构建META-INF下文件

  • 文件路径: resources/META-INF/services
  • 文件名: io.github.rothschil.spi.framework.Primate
  • 文件内容:

io.github.rothschil.spi.framework.impl.Human
io.github.rothschil.spi.framework.impl.Monkey

4.4. 验证

此处用到 ServiceLoader 类加载器,通过 Primate.class 将它的实现以此加载到 JVM 中。

4.5. 结果

验证结果


package io.github.rothschil.spi.framework;import java.util.ServiceLoader;public class TestSpi {public static void main(String[] args) {ServiceLoader<Primate> primates = ServiceLoader.load(Primate.class);for (Primate pr : primates) {pr.action();}}
}

4.5.1. ServiceLoader

ServiceLoader

属性图

ServiceLoader 本身就是一个迭代器,它的属性并不多,我们以 ServiceLoader.load 为入口,一步一步看下去。

  • 调用 ServiceLoader.load 根据当前线程调用类记载器 ClassLoader 利用 ServiceLoader 构造器,创建一个实例。
    • 类加载器
    • 访问控制器
    • 目标类
    • 迭代器
  • ServiceLoader 先判断成员变量 providers 对象中(LinkedHashMap<String,S>类型)是否有缓存实例对象,如果有缓存,直接返回
    • 读取 META-INF/services/ 下的配置文件,获得所有能被实例化的类的名称,值得注意的是, ServiceLoader 可以跨越 jar 包获取 META-INF 下的配置文件
    • 通过反射方法Class.forName()加载类对象,并用instance()方法将类实例化
    • 把实例化后的类缓存到providers对象中,(LinkedHashMap<String,S>类型)然后返回实例对象
public final class ServiceLoader<S>implements Iterable<S>
{private static final String PREFIX = "META-INF/services/";// The class or interface representing the service being loadedprivate final Class<S> service;// The class loader used to locate, load, and instantiate providersprivate final ClassLoader loader;// The access control context taken when the ServiceLoader is createdprivate final AccessControlContext acc;// Cached providers, in instantiation orderprivate LinkedHashMap<String,S> providers = new LinkedHashMap<>();// The current lazy-lookup iteratorprivate LazyIterator lookupIterator;/*** Clear this loader's provider cache so that all providers will be* reloaded.** <p> After invoking this method, subsequent invocations of the {@link* #iterator() iterator} method will lazily look up and instantiate* providers from scratch, just as is done by a newly-created loader.** <p> This method is intended for use in situations in which new providers* can be installed into a running Java virtual machine.*/public void reload() {providers.clear();lookupIterator = new LazyIterator(service, loader);}private ServiceLoader(Class<S> svc, ClassLoader cl) {service = Objects.requireNonNull(svc, "Service interface cannot be null");loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;reload();}

5. 总结

这是我们第一篇 SPI 描述,主要引入它的几个概念、用途以及与我们 API 的区别,最后我们通过一个手写的样例,虽然通过 ServiceLoader 加载的,在实际生产环境中,这存在注入线程安全以及不够灵活注入从而导致资源开销大等问题,但是这只为我们 SPI 学习加深理解,算开启正式 SPI 之旅。

相关文章:

Java SPI机制详解-01

1. 概述 SPI&#xff08;Service Provider Interface&#xff09;&#xff0c;是 Java 6 引入了一个内置功能&#xff0c;实现服务提供发现和加载机制&#xff0c;使之与特定接口的匹配。 SPI 机制的核心思想就是 解耦 &#xff0c;将装配的控制权移到程序之外&#xff0c;这…...

由浅入深C系列六:C中实现字符串trim的功能

C中实现字符串trim的功能 简介设计思路代码实现运行效果 简介 一个项目中&#xff0c;需要用c语言实现对字符串中的字定字符进行过滤并从字符串的删除&#xff0c;查询了C语言的基本库&#xff0c;没有发现有这样的函数&#xff0c;于是发挥程序员的主观能力性&#xff0c;自力…...

博客网站添加复制转载提醒弹窗Html代码

网站如果是完全禁止右键&#xff08;复制、另存为等&#xff09;操作&#xff0c;对用户来说体验感会降低&#xff0c;但是又不希望自己的原创内容直接被copy&#xff0c;今天飞飞和你们分享几行复制转载提醒弹窗Html代码。 效果展示&#xff1a; 复制以下代码&#xff0c;将其…...

ubuntu下nfs服务安装

操作系统&#xff1a;ubuntu22.04.2 一、服务端安装与配置 1、在服务端安装nfs服务端组件 sudo apt install nfs-kernel-server 2、创建共享目录share并且授权所有人可以访问 sudo mkdir /shared sudo chmod -R 777 /shared 3、配置nfs sudo vim /etc/exports 这将允许…...

Unity框架学习--2

接上文 IOC 容器是一个很方便的模块管理工具。 除了可以用来注册和获取模块&#xff0c;IOC 容器一般还会有一个隐藏的功能&#xff0c;即&#xff1a; 注册接口模块 抽象-实现 这种形式注册和获取对象的方式是符合依赖倒置原则的。 依赖倒置原则&#xff08;Dependence I…...

WebRTC音视频通话-实现GPUImage视频美颜滤镜效果iOS

WebRTC音视频通话-实现GPUImage视频美颜滤镜效果 在WebRTC音视频通话的GPUImage美颜效果图如下 可以看下 之前搭建ossrs服务&#xff0c;可以查看&#xff1a;https://blog.csdn.net/gloryFlow/article/details/132257196 之前实现iOS端调用ossrs音视频通话&#xff0c;可以查…...

82. 删除排序链表中的重复元素 II

题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 解题思路&#xff1a;设置一个新的哑元节点result&#xff0c;作为头节点&#xff0c;将head中不重复地节点依次链接到哑元节点后面&#xff0c;最后返回result.next 初始值&…...

centos 7.x 单用户模式

最近碰到 centos 7.9 一些参数设置错误无法启动系统的情况&#xff0c;研究后可以使用单用户模式进入系统进行恢复操作。 进入启动界面&#xff0c;按 e ro 替换为 rw init/sysroot/bin/sh 替换前 替换后 Ctrl-x 进行重启进入单用户模式 执行 chroot /sysroot 可以查看日…...

取证--理论

资料&#xff1a; 各比赛 Writeup &#xff1a; https://meiyacup.cn/Mo_index_gci_36.html 哔站比赛复盘视频&#xff1a; https://space.bilibili.com/453117423?spm_id_from333.337.search-card.all.click 自动分析取证四部曲 新建案例添加设备自动取证制作报告 取证大…...

Tik Tok娱乐+电商MCN怎么做?

在美国外的热门市场中&#xff0c;TikTok 主要做的区域市场包括中东、拉美、欧洲和东亚&#xff0c;而这里面适合做电商的其实并不多。 欧洲、东亚都属于成熟市场&#xff0c;且 TikTok 本身在欧洲面临 DSA 法案更严格的审查&#xff0c;与在英国相同&#xff0c;欧洲各市场消…...

java 自定义xss校验注解实现

自定义一个注解Xss。名字随意 import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Targe…...

Selenium图片滑块验证码

因为种种原因没能实现愿景的目标&#xff0c;在这里记录一下中间结果&#xff0c;也算是一个收场吧。这篇文章主要是用selenium解决滑块验证码的个别案列。 思路&#xff1a; 用selenium打开浏览器指定网站 将残缺块图片和背景图片下载到本地 对比两张图片的相似地方&#…...

CAP理论与MongoDB一致性,可用性的一些思考

正文 大约在五六年前&#xff0c;第一次接触到了当时已经是hot topic的NoSql。不过那个时候学的用的都是mysql&#xff0c;Nosql对于我而言还是新事物&#xff0c;并没有真正使用&#xff0c;只是不明觉厉。但是印象深刻的是这么一张图片&#xff08;后来google到图片来自这里&…...

lc2536.子矩阵元素加1

暴力解法&#xff1a;直接按照题目所示在矩阵的相应位置加一 时间复杂度&#xff1a;O(n2 * queries.length) 空间复杂度&#xff1a;O(1) 二维差分&#xff1a;创建二维差分数组&#xff0c;通过对差分数组的修改来影响原来的数组&#xff0c;最后还原 时间复杂度&#x…...

C#使用OpenCv(OpenCVSharp)图像全局二值化处理实例

本文实例演示C#语言中如何使用OpenCv(OpenCVSharp)对图像进行全局二值化处理。 目录 图像二值化原理 函数原型 参数说明 实例 效果 图像二值化原理...

Patch SCN一键解决ORA-600 2662故障---惜分飞

客户强制重启库之后,数据库启动报ORA-600 2037,ORA-745 kcbs_reset_pool/kcbzre1等错误 Wed Aug 09 13:25:38 2023 alter database mount exclusive Successful mount of redo thread 1, with mount id 1672229586 Database mounted in Exclusive Mode Lost write protection d…...

const、指针、引用的综合

目录 代码段 定义引用变量的技巧 内存某处 正误判定技巧 温故知新 代码段 定义引用变量的技巧 // 定义引用变量的技巧#include<iostream> using namespace std;int main() {int a 1;int * p &a;// 首先&#xff0c;定义一个指针变量int * * q1 &p;// 然…...

gitee linux免密/SSH 方式连接免登录

目录 账号密码方式免登录&#xff08;不推荐&#xff09;添加git配置新建保存密码文件git clone SSH 方式连接免登录&#xff08;推荐&#xff09;生成SSH公钥通过 ssh-keygen 程序创建找到SSH公钥 在gitee中添加公钥git clone 参考 账号密码方式免登录&#xff08;不推荐&…...

计网第一章

注意&#xff1a;计网知识点十分多&#xff0c;在本篇及后续博客主要记录个人认为比较重要的知识点。 1.计算机网络的基本概念 计算机网络就是自治的计算机互连起来的集合。计算机网络可以简称为网络&#xff0c;而互连网就是把许多网络连接起来&#xff0c;即网络的网络。 …...

windows升级记

我的笔记本原来的windows的版本是win10&#xff0c;本来想使用windows 更新下最新的补丁包&#xff0c;但是一直报错&#xff0c;出现错误号&#xff1a;0x80004005&#xff0c;在网上找了一堆的资料都没有办法解决问题,于是把问题反馈到微软的技术服务中心&#xff0c;服务中心…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡&#xff08;如 HAProxy、AWS NLB、阿里 SLB&#xff09;发起上游连接时&#xff0c;将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后&#xff0c;ngx_stream_realip_module 从中提取原始信息…...

C++中string流知识详解和示例

一、概览与类体系 C 提供三种基于内存字符串的流&#xff0c;定义在 <sstream> 中&#xff1a; std::istringstream&#xff1a;输入流&#xff0c;从已有字符串中读取并解析。std::ostringstream&#xff1a;输出流&#xff0c;向内部缓冲区写入内容&#xff0c;最终取…...

智能AI电话机器人系统的识别能力现状与发展水平

一、引言 随着人工智能技术的飞速发展&#xff0c;AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术&#xff0c;在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

PostgreSQL——环境搭建

一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在&#xff0…...

BLEU评分:机器翻译质量评估的黄金标准

BLEU评分&#xff1a;机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域&#xff0c;衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标&#xff0c;自2002年由IBM的Kishore Papineni等人提出以来&#xff0c;…...

在 Spring Boot 中使用 JSP

jsp&#xff1f; 好多年没用了。重新整一下 还费了点时间&#xff0c;记录一下。 项目结构&#xff1a; pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...