news 2026/4/23 16:53:13

Java SPI 与 Spring SPI

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java SPI 与 Spring SPI

Java SPI 是JDK 原生的服务发现机制,基于META-INF/services/目录实现,遵循「接口定义 - 实现类 - 配置文件」的约定;Spring SPI 是 Spring 框架对 Java SPI 的扩展增强,核心基于SpringFactoriesLoader类,通过META-INF/spring.factories(Spring Boot 2.7 + 推荐META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports)实现,支持按类型批量加载实现类,更适配 Spring 生态。

下面通过统一的业务场景(定义一个MessageService消息服务接口,提供不同实现),分别实现 Java SPI 和 Spring SPI,包含完整代码、配置步骤和测试用例。

一、基础准备:定义公共接口

先创建一个通用的服务接口,作为两种 SPI 机制的统一规范,后续所有实现类都需实现该接口。

java

运行

/** * 公共服务接口:消息服务 * 作为Java SPI和Spring SPI的统一规范 */ public interface MessageService { /** * 发送消息方法 * @return 消息内容 */ String sendMessage(); }

二、Java SPI 完整实现

步骤 1:创建 Java SPI 的接口实现类

创建 2 个实现类,分别模拟「短信消息服务」和「邮件消息服务」,实现MessageService接口:

java

运行

/** * Java SPI 实现类1:短信消息服务 */ public class SmsMessageService implements MessageService { @Override public String sendMessage() { return "Java SPI -> 发送短信消息"; } } /** * Java SPI 实现类2:邮件消息服务 */ public class EmailMessageService implements MessageService { @Override public String sendMessage() { return "Java SPI -> 发送邮件消息"; } }

步骤 2:创建 Java SPI 配置文件(核心约定)

Java SPI 要求严格遵循目录约定:在项目的resources目录下,创建META-INF/services/子目录,然后创建一个以接口全限定类名为文件名的纯文本文件,文件内容为实现类的全限定类名(多个实现类每行一个)。

目录结构:

plaintext

resources/ └── META-INF/ └── services/ └── com.example.spi.MessageService # 接口全限定类名作为文件名
文件内容(com.example.spi.MessageService):

plaintext

com.example.spi.impl.SmsMessageService com.example.spi.impl.EmailMessageService

注意:文件中不能有多余的空格、空行(避免加载失败),实现类必须是完整的全限定类名(包名 + 类名)。

步骤 3:Java SPI 服务加载与测试

使用 JDK 原生的java.util.ServiceLoader类加载服务实现,该类是 Java SPI 的核心加载器,通过load(接口类)方法加载所有配置的实现类,遍历即可使用。

java

运行

import java.util.ServiceLoader; /** * Java SPI 测试类 */ public class JavaSpiTest { public static void main(String[] args) { // 1. 通过ServiceLoader加载MessageService的所有实现类 ServiceLoader<MessageService> serviceLoader = ServiceLoader.load(MessageService.class); // 2. 遍历加载的实现类并调用方法 for (MessageService messageService : serviceLoader) { System.out.println(messageService.sendMessage()); } } }

Java SPI 运行结果:

plaintext

Java SPI -> 发送短信消息 Java SPI -> 发送邮件消息

三、Spring SPI 完整实现(基于 SpringFactoriesLoader)

Spring SPI 核心依赖org.springframework.core.io.support.SpringFactoriesLoader类,无需手动遍历,直接通过静态方法批量加载所有实现类,支持 Spring 的 Bean 生命周期管理,是 Spring 框架自动配置、扩展点实现的核心机制。

步骤 1:创建 Spring SPI 的接口实现类

同样实现MessageService接口,新增 2 个实现类(模拟「微信消息服务」和「钉钉消息服务」):

java

运行

/** * Spring SPI 实现类1:微信消息服务 */ public class WechatMessageService implements MessageService { @Override public String sendMessage() { return "Spring SPI -> 发送微信消息"; } } /** * Spring SPI 实现类2:钉钉消息服务 */ public class DingdingMessageService implements MessageService { @Override public String sendMessage() { return "Spring SPI -> 发送钉钉消息"; } }

步骤 2:创建 Spring SPI 配置文件(核心约定)

Spring SPI 核心配置目录为META-INF/,配置文件名为spring.factories(Spring Boot 1.x/2.x 主流用法,2.7 + 虽推荐新方式,但 spring.factories 仍兼容),文件格式为「接口全限定类名 = 实现类全限定类名」,多个实现类用英文逗号分隔。

目录结构:

plaintext

resources/ └── META-INF/ └── spring.factories # Spring SPI 核心配置文件
文件内容(spring.factories):

properties

# Spring SPI 配置:MessageService接口的实现类 com.example.spi.MessageService=com.example.spi.impl.WechatMessageService,com.example.spi.impl.DingdingMessageService

注意:等号前后无多余空格,多个实现类逗号后无空格,否则会导致类加载失败。

步骤 3:Spring SPI 服务加载与测试

使用 Spring 核心的SpringFactoriesLoader类,通过loadFactories(接口类, 类加载器)方法批量加载所有实现类(自动实例化),直接调用方法即可。

依赖说明:

需引入 Spring 核心依赖(Maven),否则无法使用SpringFactoriesLoader

xml

<!-- Spring Core 核心依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.3.29</version> <!-- 适配Spring Boot 2.7.x,可根据实际版本调整 --> <scope>compile</scope> </dependency>
测试代码:

java

运行

import org.springframework.core.io.support.SpringFactoriesLoader; import java.util.List; /** * Spring SPI 测试类 */ public class SpringSpiTest { public static void main(String[] args) { // 1. 通过SpringFactoriesLoader批量加载MessageService的所有实现类(自动实例化) List<MessageService> messageServices = SpringFactoriesLoader.loadFactories( MessageService.class, SpringSpiTest.class.getClassLoader() // 类加载器,使用当前类的类加载器即可 ); // 2. 遍历实现类并调用方法 for (MessageService messageService : messageServices) { System.out.println(messageService.sendMessage()); } } }

Spring SPI 运行结果:

plaintext

Spring SPI -> 发送微信消息 Spring SPI -> 发送钉钉消息

四、Java SPI 与 Spring SPI 核心区别

特性Java SPI(JDK 原生)Spring SPI(SpringFactoriesLoader)
核心加载类java.util.ServiceLoaderorg.springframework.core.io.support.SpringFactoriesLoader
配置文件目录 / 名称META-INF/services/接口全限定类名META-INF/spring.factories
配置格式每行一个实现类全限定类名接口全限定类名 = 实现类 1, 实现类 2(逗号分隔)
加载方式懒加载(遍历迭代器时才实例化)立即加载(调用方法直接返回所有实例化对象)
遍历方式需手动遍历ServiceLoader迭代器无需手动遍历,直接返回List集合
依赖与生态无依赖,纯 JDK 原生依赖 Spring Core,适配 Spring 生态
扩展能力基础服务发现,无额外扩展支持按类型加载、集成 Spring Bean 生命周期
典型应用JDBC 驱动加载、SLF4J 日志适配Spring Boot 自动配置、MyBatis-Spring 集成

五、关键注意事项

  1. 类全限定名必须准确:两种 SPI 的配置文件中,接口和实现类的全限定类名(包名 + 类名)不能写错,否则加载失败且无明显报错;
  2. 实现类必须有无参构造器:SPI 机制通过反射实例化实现类,默认调用无参构造器,若实现类只有有参构造器,会抛出InstantiationException
  3. 配置文件无多余空格 / 空行:Java SPI 的配置文件每行一个实现类,Spring SPI 的等号 / 逗号前后无空格,否则会被识别为类名的一部分,导致类加载失败;
  4. Spring Boot 2.7+ 配置变更:Spring Boot 2.7 开始推荐使用META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports替代spring.factories,文件内容为自动配置类的全限定类名(每行一个),适用于自动配置场景,普通 SPI 仍可使用spring.factories
  5. 类加载器一致性:加载 SPI 实现类时,需保证使用的类加载器能加载到接口和实现类(通常使用当前类的类加载器即可),避免类加载器隔离导致的加载失败。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 17:49:15

【dz-697】基于单片机的智能保温杯设计

摘要&#xff1a; 在快节奏的现代生活中&#xff0c;人们常常因为忙碌而忽视了基本的健康习惯&#xff0c;比如定时饮水。为了改善这一状况&#xff0c;智能保温杯应运而生&#xff0c;不仅能够提醒用户定时饮水&#xff0c;还能保持饮品在最佳温度&#xff0c;从而提升生活质…

作者头像 李华
网站建设 2026/4/16 11:37:41

一文读懂水控一体机:构造、原理全解析,节水又省心!

&#xff08;一&#xff09;什么是水控一体机&#xff08;1&#xff09;内部构造水控一体机主要由电子控制模块、IC卡和发讯基表三个关键部分组成&#xff0c;它们相互协作&#xff0c;共同实现对水的精细控制&#xff0c;达到节约用水的目的。电子控制模块是水控一体机的“智慧…

作者头像 李华
网站建设 2026/4/23 3:42:30

开发早餐食谱推荐工具,输入食材耗时(5/10/15分钟),推荐简单易做的早餐,附带步骤,支持收藏,帮上班族快速搞定早餐营养不将就。

1. 实际应用场景与痛点 场景 上班族早晨时间紧张&#xff0c;常常&#xff1a; - 来不及准备早餐&#xff0c;随便吃点零食或直接空腹上班 - 想吃得健康但不知道做什么 - 食材有限&#xff0c;需要根据家里现有的东西推荐 - 收藏喜欢的食谱&#xff0c;方便重复使用 痛点 1.…

作者头像 李华
网站建设 2026/4/18 9:41:04

导师严选8个降AIGC工具,千笔帮你彻底降AI率

AI降重工具&#xff1a;论文写作的“隐形助手” 在当今学术写作中&#xff0c;AI生成内容&#xff08;AIGC&#xff09;已经成为许多学生论文中的常见现象。然而&#xff0c;随着高校对论文原创性的要求日益严格&#xff0c;如何有效降低AIGC率、去除AI痕迹、同时保持语义通顺&…

作者头像 李华
网站建设 2026/4/18 11:54:34

DeepSeek-R1技术革命:从开源突破到推理优化,大模型开发者的进阶之路

DeepSeek-R1发布一周年之际&#xff0c;其开源项目FlashMLA更新暗示MODEL1(可能是R2)即将推出。R1通过降低技术、采用和心理三重壁垒&#xff0c;将高级推理能力转变为可复用工程资产&#xff0c;采用推理优先训练目标聚焦数学与逻辑推导&#xff0c;形成稳定推理结构。它改变了…

作者头像 李华