文章目录

  • 1. 基本概念
  • 2. 使用场景
  • 3. 使用要求
  • 4. JDK SPI 实现
  • 5. Spring SPI 实现

1. 基本概念

SPI (Service Provider Interface), 是 Java 提供的一套用来被第三方实现或者扩展的 API, 它可以用来启用框架扩展和替换组件

Java SPI 实际上是“基于接口的编程+策略模式+配置文件”组合实现的动态加载机制

2. 使用场景

  • 数据库驱动
  • 日志 SLF4J
  • Spring 使用 SPI
  • Dubbo 使用 SPI, 但对原生 SPI 做了封装, 允许用户扩展实现 Filter 接口

3. 使用要求

要使用 SPI, 需要遵循如下约定

  • SPI 的实现类中必须有一个无参的构造方法
  • 当服务提供者提供了接口的实现, 在 jar 包的 META-INF 目录下创建一个以“接口全限定名”为命名的文件, 内容为实现类的全限定名
  • JDK 中路径时 META-INF/services/
  • Spring 中配置是 META-INF/spring.factories
  • 接口实现类所在的 jar 包放在主程序的 classpath 中
  • 通过 Loader 类将 META-INF 目录下的配置文件加载, 解析文件中的全限定名类名, 将类加载到 JVM
  • JDK 中是使用的是 ServiceLoader 加载 META-INF/services/ 下的文件
  • Spring 中使用的是 SpringFactoriesLoader 加载 META-INF/spring.factories

4. JDK SPI 实现

对数据库驱动源码分析

MySQL 驱动是 om.mysql.cj.jdbc 包下 Driver 实现了接口 JDK 的 java.sql.Driver, 并在 META-INF/services 目录下创建文件名为 java.sql.Driver 的文件, 在文件里填写实现类的全路径信息 com.mysql.cj.jdbc.Driver

// 实现 JDK 的 java.sql.Driver 类
public class Driver extends NonRegisteringDriver implements java.sql.Driver {// SPI 的实现类中必须有一个无参的构造方法public Driver() throws SQLException {}static {try {DriverManager.registerDriver(new Driver());} catch (SQLException var1) {throw new RuntimeException("Can't register driver!");}}
}

查看 java.util.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 可以跨越 jar 包获取 META-INF/services 目录下的配置文件

try {String fullName = PREFIX + service.getName();if (loader == null)configs = ClassLoader.getSystemResources(fullName);elseconfigs = loader.getResources(fullName);
} catch (IOException x) {fail(service, "Error locating configuration files", x);
}

获取实现类的全类名后, 通过反射方法 Class.forName() 加载类对象

5. Spring SPI 实现

Spring 的 SPI 实现是由 org.springframework.core.io.support 包下的 SpringFactoriesLoader 实现的, 配置文件路径是 META-INF/spring.factories 与 JDK 有差异

public final class SpringFactoriesLoader {public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";public static <T> List<T> loadFactories(Class<T> factoryClass, @Nullable ClassLoader classLoader) {}private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {...// 扫描 jar 包下 META-INF/spring.factories 文件Enumeration<URL> urls = (classLoader != null ?classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));...}
}

在 Spring 的 spring-data-redis 中对 JDK 和 Spring 都做了 SPI 实现

[04][02][02] SPI 机制相关推荐

  1. Java中的ClassLoader和SPI机制

    深入探讨 Java 类加载器 成富是著名的Java专家,在IBM技术网站发表很多Java好文,也有著作. 线程上下文类加载器 线程上下文类加载器(context class loader)是从 JDK ...

  2. Java的SPI机制

    Dubbo等框架使用到必须掌握. java.sql.Driver 是 Spi,com.mysql.jdbc.Driver 是 Spi 实现,其它的都是 Api. package org.hadoop. ...

  3. JDK/Dubbo/Spring 三种 SPI 机制,谁更好?

    点击关注公众号,Java干货及时送达 来源:juejin.cn/post/6950266942875779108 SPI 全称为 Service Provider Interface,是一种服务发现机 ...

  4. motan源码分析二:使用spi机制进行类加载

    在motan的源码中使用了很多的spi机制进行对象的创建,下面我们来具体分析一下它的实现方法. 1.在实际的jar包的\META-INF\services目录中引入相关的文件,例如下图中,我解压了co ...

  5. Java是如何实现自己的SPI机制的? JDK源码(一)

    注:该源码分析对应JDK版本为1.8 1 引言 这是[源码笔记]的JDK源码解读的第一篇文章,本篇我们来探究Java的SPI机制的相关源码. 2 什么是SPI机制 那么,什么是SPI机制呢? SPI是 ...

  6. Motan的SPI机制实现分析

    Motan使用SPI机制来实现模块间的访问,基于接口和name来获取实现类,降低了模块间的耦合. 首先来看一下使用方式: 有两个注解 @Documented@Retention(RetentionPo ...

  7. Flink从入门到精通100篇(十一)-Java SPI 机制在 Flink SQL 中的应用

    Java SPI 机制简介 Java SPI机制,即Java Service Provider Interface,是Java提供的基于"接口编程 + 策略模式 + 配置文件"组合 ...

  8. 深入理解java SPI机制

    What? SPI机制(Service Provider Interface)其实源自服务提供者框架(Service Provider Framework,参考[EffectiveJava]page6 ...

  9. JDK源码分析——Java的SPI机制分析与实战

    重点提示:在我博客中的所有的源码分析的实例,我都将会放到github上,感兴趣的朋友可以下载下来调试运行,我相信还是可以有所收获的.我的目的是让所有读到我博客的朋友都可以了解到有价值的东西,学习到ja ...

  10. 高级开发必须理解的Java中SPI机制

    本文通过探析JDK提供的,在开源项目中比较常用的Java SPI机制,希望给大家在实际开发实践.学习开源项目提供参考. 1 SPI是什么 SPI全称Service Provider Interface ...

最新文章

  1. php104.tmp,ThinkPHP5.0多个文件上传后找不到临时文件的修改方法
  2. 谈C/C++指针精髓
  3. JavaScript 变量克隆和判断变量类型
  4. 模板:BSGS(数论)
  5. Spring 中的国际化Message的简单例子(ApplicationContext) 不跟框架集成的版本
  6. 加载中_GIS地图在项目中的加载显示
  7. CVPR2021 | MIMO-VRN 用于视频缩放任务的联合训练策略
  8. Java Web学习总结(28)——Java Web项目MVC开源框架SSH和SSM比较
  9. 循证e刊 安慰剂的前世今生
  10. AD画图器件变灰如何恢复SHIFT+C清除过滤器
  11. python怎么写判断语句_Python中的if判断语句入门
  12. 已在该编译单元中定义_LLVM中的pass及其管理机制
  13. ACM解题总结——HihoCoder1199 (微软笔试题)
  14. spring boot 集成 websocket 实现消息主动推送
  15. cmos存储器中存放了_CMOS存储器里放哪些东西
  16. 这14种嵌入式实时系统,你用过哪些?
  17. js 三大家族(offset/scroll/client)
  18. VS2005中文版下载地址和msdn_vs2005中文版
  19. LED驱动电源各项指标测试方法
  20. 【PaperReading】The permutation testing approach: a review

热门文章

  1. LaTex插入图片的几种常用的详细方法
  2. Linux-禁止某些IP访问
  3. Java常用方法:StringUtils工具类、去除空格的函数、手机号中间4位换成*、判断字符是否为数字
  4. 使用PHP辅助快速制作一套自己的手写字体实践
  5. 通过Excel快捷生成折线图
  6. 安装nginx并绑定域名
  7. 经济地理学复习要点总结(完整)
  8. setw(),setfill() 和左右对齐 控制输出流的格式
  9. 从市场需求目标看数据分析演进方向
  10. 台州高防ip是什么原理?台州世通兰陵王为你解答