SPI概述

1.SPI概念

①全称:Service Provider Interface
②是什么:是Java提供的一套用来被第三方实现或者扩展接口,从JDBC4.0,JDK6开始Java实现了SPI机制
③作用:用来启用框架扩展和替换组件,为这些被扩展的API寻找服务实现

2.SPI和API区别

概念 实现方 调用方 使用人员
API 制定接口并完成对接口的实现 仅仅依赖接口调用,且无权选择不同实现 应用开发人员
SPI 制定接口规范,提供给外部来实现,在调用时则选择自己需要的外部实现 框架扩展人员使用

3.SPI简单示例

①定义一个接口

package com.lemon.spi;/*** @author lemon* @Desc* @date 2020-09-22 11:14*/
public interface RenShu {void renShu();
}

②定义两个接口实现类

package com.lemon.spi;/*** @author lemon* @Desc* @date 2020-09-22 11:18*/
public class ShenLuoTianZheng implements RenShu{@Overridepublic void renShu() {System.out.println("神罗天征1!");}
}
package com.lemon.spi;/*** @author lemon* @Desc* @date 2020-09-22 11:19*/
public class WanXiangTianYin implements RenShu{@Overridepublic void renShu() {System.out.println("万象天引1!");}
}

③在resources下(非固定,只要相对路径是META-INF/services/接口全路径名)新建package META_INF和services,在services下新建和接口名相同的文件

④新建测试类

package com.lemon.spi;import java.util.ServiceLoader;/*** @author lemon* @Desc* @date 2020-09-22 11:10*/
public class Test {public static void main(String[] args) {ServiceLoader<RenShu> renShus = ServiceLoader.load(RenShu.class);for(RenShu renShu:renShus){renShu.renShu();}}
}

4.SPI源码分析

①ServiceLoader类实现流程

核心代码
①:实例化ServiceLoader及私有内部类LazyIteratorpublic 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();}
②进行迭代,实际调用的是LazyIterator的hasNextService与nextService方法
private boolean hasNextService() {if (nextName != null) {return true;}if (configs == null) {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);}}while ((pending == null) || !pending.hasNext()) {if (!configs.hasMoreElements()) {return false;}pending = parse(service, configs.nextElement());}nextName = pending.next();return true;}private S nextService() {if (!hasNextService())throw new NoSuchElementException();String cn = nextName;nextName = null;Class<?> c = null;try {//反射加载类c = Class.forName(cn, false, loader);} catch (ClassNotFoundException x) {fail(service,"Provider " + cn + " not found");}if (!service.isAssignableFrom(c)) {fail(service,"Provider " + cn  + " not a subtype");}try {//实例化S p = service.cast(c.newInstance());//放进缓存providers.put(cn, p);return p;} catch (Throwable x) {fail(service,"Provider " + cn + " could not be instantiated",x);}throw new Error();          // This cannot happen}

5.JDBC的SPI


com.mysql.cj.jdbc.Driver是其默认的实现类

public class DriverManager {// List of registered JDBC driversprivate final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();private static volatile int loginTimeout = 0;private static volatile java.io.PrintWriter logWriter = null;private static volatile java.io.PrintStream logStream = null;// Used in println() to synchronize logWriterprivate final static  Object logSync = new Object();/* Prevent the DriverManager class from being instantiated. */private DriverManager(){}/*** Load the initial JDBC drivers by checking the System property* jdbc.properties and then use the {@code ServiceLoader} mechanism*/static {//此处进行spi机制调用loadInitialDrivers();println("JDBC DriverManager initialized");}private static void loadInitialDrivers() {String drivers;try {drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {public String run() {return System.getProperty("jdbc.drivers");}});} catch (Exception ex) {drivers = null;}// If the driver is packaged as a Service Provider, load it.// Get all the drivers through the classloader// exposed as a java.sql.Driver.class service.// ServiceLoader.load() replaces the sun.misc.Providers()AccessController.doPrivileged(new PrivilegedAction<Void>() {public Void run() {//此处进行迭代扫描ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);Iterator<Driver> driversIterator = loadedDrivers.iterator();/* Load these drivers, so that they can be instantiated.* It may be the case that the driver class may not be there* i.e. there may be a packaged driver with the service class* as implementation of java.sql.Driver but the actual class* may be missing. In that case a java.util.ServiceConfigurationError* will be thrown at runtime by the VM trying to locate* and load the service.** Adding a try catch block to catch those runtime errors* if driver not available in classpath but it's* packaged as service and that service is there in classpath.*/try{while(driversIterator.hasNext()) {driversIterator.next();}} catch(Throwable t) {// Do nothing}return null;}});

6.SPI优缺点

优点:
1.不需要改动源码就可以实现扩展,解耦。
2.实现扩展对原来的代码几乎没有侵入性。
3.只需要添加配置就可以实现扩展,符合开闭原则。

缺点:
1.不能按需加载,需要遍历所有的实。如果不想用某些实现类,或者某些类实例化很耗时,它也被载入并实例化了,这就造成了浪费。
2.ServiceLoader 线程不安全。

参考链接: https://www.cnblogs.com/jy107600/p/11464985.html

JAVA SPI机制概述相关推荐

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

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

  2. Java SPI机制详解

    Java SPI机制详解 1.什么是SPI? 2.SPI的用途 Driver实现 Mysql DriverManager实现 spi工具类`ServiceLoader` 将自己注册到驱动管理器的驱动列 ...

  3. Java SPI机制实现插件化扩展功能

    Java SPI机制实现插件化扩展功能 1.背景 我们有一个图数据库的服务,用户希望在不修改现有源代码的情况下扩展自定义的分词器,达到可插件式扩展功能的目标. 通过Java的SPI机制实现插件式的扩展 ...

  4. 深入理解java SPI机制

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

  5. JAVA SPI机制及SPI机制在Tomcat中的应用

    SPI 是 JAVA 提供的一种服务提供发现接口,其实就是一种面向接口的编程,为接口去匹配具体服务实现的机制,这一点上与 IOC 的思想类似,都是把装配的控制权放到了程序之外,下面具体看看什么是 SP ...

  6. java spi机制_Java是如何实现自己的SPI机制的? JDK源码(一)

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

  7. java spi技术,Java SPI机制

    Java组件一个更为人熟知的名词"服务",与流行的微服务有所区别. 以往加载JDBC驱动使用如下方式:Class.forName() Java 1.6引入SPI机制,使用Drive ...

  8. java spi机制_Java 双亲委派机制的破坏—SPI机制

    作者:程序猿微录 出自:TinyRecord 原文:tinyice.cn/articles/123 Java 双亲委派机制的破坏-SPI机制 在Java的类加载机制中,默认的就是双亲委派机制,这种委派 ...

  9. Java SPI机制分析

    2019独角兽企业重金招聘Python工程师标准>>> SPI概述 SPI全称为(Service Provider Interface) ,是JDK内置的一种服务提供发现机制:主要被 ...

最新文章

  1. Python实现五子棋人机对战 | CSDN博文精选
  2. LeetCode ZigZag Conversion
  3. 采购订单模板_电子信息制造业解决方案,电子工业采购监管、管理、降本可控化...
  4. 3.Spring Cloud Alibaba教程:Nacos服务注册与发现
  5. onlyoffice修改字号
  6. 编程一个最简单游戏_通过一个简单的数学游戏,清晰了解各大编程语言之间的一些区别...
  7. 图像分类 数据准备(将文件夹中所有图片路径写到TXT文件中)
  8. 实业逻辑与品牌逻辑的矛盾
  9. java timer 返回值,如何让计时器返回java时间
  10. jsf tree组件_JSF UI组件标签属性示例教程
  11. HP 8440P 4G内存蓝屏--内存颗粒容量支持问题
  12. word中去除页眉中的横线
  13. 【Matlab】imresize的用法
  14. python做数据分析时缺失值填补、缺失值填充方法汇总
  15. 小凯机器人软件_Cruzr-Cruzr(机器人控制软件)下载 v1.5.20190706.48官方版--pc6下载站...
  16. Linux期末复习笔记(太原理工大学)
  17. 学python多大年龄可以学车_考驾照要多大年龄?
  18. Java开发记事本(完整版)
  19. 2023第三方应用苹果电脑磁盘读写工具Tuxera NTFS
  20. ArcGIS环境搭建及地图服务发布

热门文章

  1. kill不掉mysqld
  2. Windows 右下角 输入法 图标 不见了 显示输入法 图标 绝对成功
  3. 关于google earth engine(GEE)的一些想法与大胆预测
  4. 那些年,我与IE的爱恨别离(一)
  5. java 新浪短链接_java生成短连接(调用新浪微博api生成)
  6. 最新kali之radare2
  7. Vigenere算法如何进行加密操作?
  8. Flutter Widget 之 Expanded(填充布局)
  9. vue层叠轮播slider插件
  10. 移动appium测试必知必会(一)