Java的SPI机制详解

SPI的核心概念

Java的SPI(Service Provider Interface)机制是一种服务发现机制,允许框架或核心库动态加载第三方实现,实现接口与实现类的解耦。它通过配置文件声明服务提供者,并由ServiceLoader类在运行时加载这些实现。

目的
解耦接口定义与具体实现,使程序在运行时能动态发现并加载服务提供者,支持扩展性。

角色划分

  • 服务接口:由框架或核心库定义的接口(如java.sql.Driver)。
  • 服务提供者:第三方实现的接口类(如MySQL的com.mysql.cj.jdbc.Driver)。
  • 配置文件:在META-INF/services/下声明服务提供者的类路径。

SPI的工作原理

  1. 配置文件规则
    (1). 文件位置:META-INF/services/<接口全限定名>。
    (2). 文件内容:每行一个实现类的全限定名(如com.mysql.cj.jdbc.Driver)。

  2. 加载流程
    通过ServiceLoader.load(Class接口类)加载实现类:
    (1). 扫描所有JAR包的META-INF/services目录。
    (2). 根据接口名找到配置文件,读取实现类名。
    (3). 通过反射实例化实现类。

    	ServiceLoader<PaymentService> loader = ServiceLoader.load(PaymentService.class);for (PaymentService service : loader) {service.pay(); // 调用具体实现}
    

SPI的优缺点

优点缺点
解耦接口与实现,扩展性强配置文件的路径和格式严格,易出错
动态加载,无需修改核心代码实现类需有无参构造器,反射可能影响性能
支持多厂商实现(如不同数据库驱动)多线程下需注意ServiceLoader的线程安全

SPI vs API

特性SPIAPI
定义方由调用方定义接口(如Java核心库)由实现方定义接口(如第三方库)
实现方第三方提供实现调用方直接使用实现方提供的接口
控制反转调用方控制接口,实现方扩展实现方控制接口,调用方依赖
典型应用JDBC驱动、日志框架普通类库(如Apache HttpClient)

SPI的使用步骤(以支付接口为例)

  1. 定义服务接口

    public interface PaymentService {void pay();
    }
    
  2. 实现服务接口

    public class AlipayService implements PaymentService {@Overridepublic void pay() { System.out.println("支付宝支付"); }
    }
    
  3. 添加配置文件

    文件路径:src/main/resources/META-INF/services/com.example.PaymentService

    com.example.AlipayService
    com.example.WechatPayService
    
  4. 加载服务

    public class PaymentDemo {public static void main(String[] args) {ServiceLoader<PaymentService> services = ServiceLoader.load(PaymentService.class);for (PaymentService service : services) {service.pay(); // 输出:支付宝支付、微信支付}}
    }
    

SPI的典型应用场景

  • JDBC驱动加载

    • JDBC 4.0后通过SPI自动注册驱动,无需Class.forName()。
    • MySQL驱动JAR包中的配置文件:
      META-INF/services/java.sql.Driver → com.mysql.cj.jdbc.Driver。
  • 日志门面框架
    SLF4J通过SPI动态绑定Logback、Log4j2等实现。

  • 序列化框架
    Jackson、Fastjson等可通过SPI扩展序列化器。

注意事项

  1. 配置文件的准确性
    确保文件名和内容正确,避免拼写错误。

  2. 实现类的无参构造器
    ServiceLoader通过反射实例化类,要求实现类必须有无参构造器。

  3. 线程安全
    ServiceLoader非线程安全,需在多线程环境下自行处理同步。

  4. 类加载器问题
    在复杂类加载环境(如OSGi)中,可能需要指定类加载器:

    ServiceLoader.load(PaymentService.class, customClassLoader);
    

总结

SPI机制通过动态服务发现,为Java应用提供了高度扩展性。其核心在于接口与实现的解耦,允许第三方按需扩展功能,常见于数据库驱动、日志框架等场景。使用时需注意配置文件的规范性和类加载机制的影响。

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

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

相关文章

【QT】文件系统相关 -- QFile

一、Qt 文件概述 &#x1f525; 文件操作是应用程序必不可少的部分。Qt 作为⼀个通用开发库&#xff0c;提供了跨平台的文件操作能力。Qt 提供了很多关于⽂件的类&#xff0c;通过这些类能够对文件系统进行操作&#xff0c;如文件读写、文件信息获取、文件制或重命名等 二、输…

EasyCVR安防视频汇聚平台助力工业园区构建“感、存、知、用”一体化智能监管体系

在现代工业园区的安全管理和高效运营中&#xff0c;视频监控系统扮演着不可或缺的角色。然而&#xff0c;随着园区规模的扩大和业务的复杂化&#xff0c;传统的视频监控系统面临着诸多挑战&#xff0c;如设备众多难以统一管理、数据存储分散、智能分析能力不足、信息利用率低下…

鸿蒙路由 HMrouter 配置及使用一

1、学习链接 HMRouter地址 https://gitee.com/hadss/hmrouter/blob/dev/HMRouterLibrary/README.md 2、工程配置 下载安装 ohpm install hadss/hmrouter 添加编译插件配置 在工程目录下的build-profile.json5中&#xff0c;配置useNormalizedOHMUrl属性为true (我这项目创…

Tcp网络通信的基本流程梳理

先来一张经典的流程图 接下介绍一下大概流程&#xff0c;各个函数的参数大家自己去了解加深一下印象 服务端流程 1.创建套接字&#xff1a;使用 socket 函数创建一个套接字&#xff0c;这个套接字后续会被用于监听客户端的连接请求。 需要注意的是&#xff0c;服务端一般有俩…

Nexus File类型Blob Stores迁移至Minio操作指南(下)

#作者&#xff1a;闫乾苓 文章目录 迁移步骤停止nexus3服务备份nexus原始数据修改Blob Stores中元数据文件中类型为s3将Blob Stores中的二进制构件文件数据复制s3&#xff08;minio&#xff09;存储修改OrientDB中相关Blob Stores的属性修复OrientDB的文件权限开启nexus3服务迁…

mapbox基础,使用线类型geojson加载symbol符号图层,用于标注文字

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️symbol符号图层样式1.4 ☘️line线图层…

《C语言中“输入魔法师”:scanf函数的奥秘与技巧》

&#x1f680;个人主页&#xff1a;fasdfdaslsfadasdadf &#x1f4d6;收入专栏&#xff1a;C语言 &#x1f30d;文章目入 一、引言二、scanf函数的基本语法三、格式说明符的种类及用法&#xff08;一&#xff09;整数输入&#xff08;二&#xff09;浮点数输入&#xff08;三&…

Quickwit+Jaeger+Prometheus+Grafana搭建Java日志管理平台

介绍 生产服务应用可观测性在当下比较流行的方案&#xff0c;其中出现了大量高性能、开箱即用、易上手的的开源产品&#xff0c;大大丰富了在可观测性领域产品的多样性&#xff0c;本文讲述基于OTLP协议推送Java项目遥测数据&#xff08;日志、指标、链路&#xff09;到后端存储…

Unity Timeline 扩展

这里认为大家已经会timeline的基本使用了&#xff0c;只介绍怎么自定义扩展。 第一步.自定义Track 首先要自定义一条轨道。剪辑是要在轨道里跑的&#xff0c;系统自带的轨道我们加不了自定义剪辑&#xff0c;得新建自己用的。这个很简单。 [TrackClipType(typeof(TransformTw…

文生图技术的演进、挑战与未来:一场重构人类创造力的革命

摘要 文生图&#xff08;Text-to-Image Generation&#xff09;技术作为生成式人工智能&#xff08;Generative AI&#xff09;的核心分支&#xff0c;正在以颠覆性力量重塑内容生产范式。本文系统梳理文生图技术从早期实验到多模态大模型的演进路径&#xff0c;分析其在设计、…

如何手动使用下载并且运行 QwQ-32B-GGUF

首先使用安装 pip install ModelScope 使用 ModelScope 下载对应的模型 modelScope download --model Qwen/QwQ-32B-GGUF qwq-32b-q4_k_m.gguf 第二步开始下载 ollama git clone https://githubfast.com/ggerganov/llama.cpp # githubfast.com 可以加速下载 切换到目录&am…

SPring 学习积累1 关于下载相关jdk maven 版本

3.15.1 注意下载的版本 有些是不适配的&#xff0c;官网有提示&#xff1b; 3.15.2 注意配置环境变量时需要注意admistartor 中的java路径和系统变量是否一致&#xff0c;一行要一致&#xff0c;不然后续安装maven之后&#xff0c;使用命令 mvn -version时会显示以下错误&…

Excel(函数篇):Vlookup函数 详细用法

目录 Vlookup函数基础用法精确查找易错问题员工信息查询表 进阶用法近似匹配&#xff08;模糊查找&#xff09;结合通配符查找反向查找 高级技巧多条件查找动态列查询 错误处理屏蔽错误值处理数字/文本格式问题注意事项常见错误解决方案 拓展用法跨表与跨工作簿查找查找返回多列…

对最近的刷题做一个小总结(关于动态规划和贪心)

文章目录 1. 小总结2. 两道算法题2.1 数组中两个字符串的最小距离2.2 孩子们的游戏 1. 小总结 最近刷了很多算法题&#xff0c;真正了解到的算法应是dfs&#xff0c;多元dfs&#xff0c;以及动态规划和贪心。 dfs和多元dfs目前并没有真正深入研究过&#xff0c;不过熟悉套路之…

jmeter分布式原理及实例

一、执行原理 二、相关注意事项 关闭防火墙所有上网控制机、代理机、服务器都在同一个网络上所有机器的jmeter和java版本必须一致关闭RMI.SSL开关 三、配置和执行 配置&#xff1a; 修改bin/jmeter.properties文件&#xff1a; 代理机&#xff1a; 修改服务端口&#xff1…

C++ STL 详解 ——vector 的深度解析与实践指南

一、vector 的核心概念与底层机制 1.1 动态数组的本质 连续内存存储&#xff1a;与普通数组相同&#xff0c;vector 使用连续的内存空间&#xff0c;支持 O (1) 时间复杂度的随机访问。动态扩容特性&#xff1a;通过push_back等操作自动调整容量&#xff0c;无需手动管理内存…

【SpringBoot】——在做一些项目中所学到的新的技术栈和一些小技巧(主要为MQ,详细请看目录和文章)

&#x1f3bc;个人主页&#xff1a;【Y小夜】 &#x1f60e;作者简介&#xff1a;一位双非学校的大三学生&#xff0c;编程爱好者&#xff0c; 专注于基础和实战分享&#xff0c;欢迎私信咨询&#xff01; &#x1f386;入门专栏&#xff1a;&#x1f387;【MySQL&#xff0…

0经验cursor开发一款跨端app

设备&#xff1a;mac电脑cursor 1.输入诉求 我要实现一个跨端的地址应用&#xff0c;使其可以在ios、安卓、小程序和网页端都可以使用。这是一个demo的项目&#xff0c;功能不必要太过复杂&#xff0c;下面需要你和我多次沟通完成这个任务。你先根据我的内容输入&#xff0c…

Element Ui - 编辑时表单校验信息未清空问题处理

Element Ui 关闭对话框清空验证消息&#xff0c;清除form表单的操作 首先在对话框 取消按钮 添加 click事件&#xff0c;例如&#xff1a;&#xff08;ps&#xff1a;callOf 里面的addGroupData和ref - - &#xff09; <div slot"footer" class"dialog-foo…

OpenCV图像加权函数:addWeighted

1 addWeighted函数 在OpenCV 里&#xff0c;addWeighted 函数的作用是对两个图像进行加权求和&#xff0c;常用于图像融合、图像过渡等场景。函数如下&#xff1a; cv2.addWeighted(src1, alpha, src2, beta, gamma[, dst[, dtype]])2 参数解释 src1&#xff1a;第一个输入图…