什么是SPI和API

Application Programming Interface (API)?

  • The API is the description of classes/interfaces/methods/... that you call and use to achieve a goal, and

  • the SPI is the description of classes/interfaces/methods/... that you extend and implement to achieve a goal.

SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制。SPI是一种动态替换发现的机制, 比如有个接口,想运行时动态的给它添加实现,你只需要添加一个实现。我们经常遇到的就是java.sql.Driver接口,其他不同厂商可以针对同一接口做出不同的实现,mysql和postgresql都有不同的实现提供给用户,而Java的SPI机制可以为某个接口寻找服务实现。

首先放个图:我们在“调用方”和“实现方”之间需要引入“接口”,可以思考一下什么情况应该把接口放入调用方,什么时候可以把接口归为实现方。

先来看看接口属于实现方的情况,这个很容易理解,实现方提供了接口和实现,我们可以引用接口来达到调用某实现类的功能,这就是我们经常说的api,它具有以下特征:

  1. 是对实现的说明(我可以给你提供什么)

  2. 组织上位于实现方所在的包中

  3. 实现和接口在一个包中

当接口属于调用方时,我们就将其称为spi,全称为:service provider interface,spi的规则如下:

  1. 是对实现的约束(要提供这个功能,实现者需要做那些事情)

  2. 组织上位于调用方所在的包中

  3. 实现位于独立的包中(也可认为在提供方中)

简而言之

API会告诉您特定的类/方法为您执行什么操作,而SPI则告诉您必须执行哪些操作才能符合要求。通常,API和SPI是分开的。例如,在JDBC中,Driver类是SPI的一部分:如果只想使用JDBC,则不需要直接使用它,但是实现JDBC驱动程序的每个人都必须实现该类。但是,有时它们会重叠。Connection接口既是SPI,又是API:您在使用JDBC驱动程序时通常会使用它,并且需要由JDBC驱动程序的开发人员来实现。

JDK

在jdk6里面引进的一个新的特性ServiceLoader,从官方的文档来说,它主要是用来装载一系列的service provider。而且ServiceLoader可以通过service provider的配置文件来装载指定的service provider。当服务的提供者,提供了服务接口的一种实现之后,我们只需要在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。 可能上面讲的有些抽象,下面就结合一个示例来具体讲讲。

public interface Search {
  public List<String> searchDoc(String keyword);  
}

文件搜索实现

public class FileSearch implements Search{
  @Override
  public List<String> searchDoc(String keyword) {
      System.out.println("文件搜索 "+keyword);
      return null;
  }
}

数据库搜索实现

public class DatabaseSearch implements Search{
  @Override
  public List<String> searchDoc(String keyword) {
      System.out.println("数据搜索 "+keyword);
      return null;
  }
}

接下来可以在resources下新建META-INF/services/目录,然后新建接口全限定名的文件:com.cainiao.ys.spi.learn.Search,里面加上我们需要用到的实现类

com.github.spi.learn.FileSearch

测试

public class TestCase {
  public static void main(String[] args) {
      ServiceLoader<Search> s = ServiceLoader.load(Search.class);
      Iterator<Search> iterator = s.iterator();
      while (iterator.hasNext()) {
          Search search = iterator.next();
          search.searchDoc("hello world");
      }
  }
}

可以看到输出结果:文件搜索 hello world

如果在com.github.spi.learn.Search文件里写上两个实现类,那最后的输出结果就是两行了。 这就是因为ServiceLoader.load(Search.class)在加载某接口时,会去META-INF/services下找接口的全限定名文件,再根据里面的内容加载相应的实现类。

这就是spi的思想,接口的实现由provider实现,provider只用在提交的jar包里的META-INF/services下根据平台定义的接口新建文件,并添加进相应的实现类内容就好。

那为什么配置文件为什么要放在META-INF/services下面? 可以打开ServiceLoader的代码,里面定义了文件的PREFIX如下:

private static final String PREFIX = "META-INF/services/"

Java SPI的使用很简单。也做到了基本的加载扩展点的功能。但Java SPI有以下的不足:

  • 需要遍历所有的实现,并实例化,然后我们在循环中才能找到我们需要的实现。

  • 配置文件中只是简单的列出了所有的扩展实现,而没有给他们命名。导致在程序中很难去准确的引用它们。

  • 扩展如果依赖其他的扩展,做不到自动注入和装配

  • 不提供类似于Spring的IOC和AOP功能

  • 扩展很难和其他的框架集成,比如扩展里面依赖了一个Spring bean,原生的Java SPI不支持

什么是JDK的SPI机制的更多相关文章

  1. dubbo源码分析4——SPI机制_ExtensionFactory类的作用

    ExtensionFactory的源码: @SPI public interface ExtensionFactory { /** * Get extension. * * @param type o ...

  2. NIO 源码分析(04) 从 SelectorProvider 看 JDK SPI 机制

    目录 一.SelectorProvider SPI 二.SelectorProvider 加载过程 2.1 SelectorProvider 加载 2.2 Windows 下 DefaultSelec ...

  3. JDK源码系列(一) ------ 深入理解SPI机制

    什么是SPI机制 最近我建了另一个文章分类,用于扩展JDK中一些重要但不常用的功能. SPI,全名Service Provider Interface,是一种服务发现机制.它可以看成是一种针对接口实现 ...

  4. jdk和dubbo的SPI机制

    前言:开闭原则一直是软件开发领域中所追求的,开闭原则中的"开"是指对于组件功能的扩展是开放的,是允许对其进行功能扩展的,“闭”,是指对于原有代码的修改是封闭的,即不应该修改原有的代 ...

  5. JDK SPI 机制

    一.概述 最早看到 SPI 这个机制是在 dubbo 实现 中,最近发现原来也不是什么新东西,竟然就是 JDK 中内置的玩意,今天就来一探究竟,看看它到底是什么玩意! SPI的全称是 Service ...

  6. Dubbo的SPI机制与JDK机制的不同及原理分析

    从今天开始,将会逐步介绍关于DUbbo的有关知识.首先先简单介绍一下DUbbo的整体概述. 概述 Dubbo是SOA(面向服务架构)服务治理方案的核心框架.用于分布式调用,其重点在于分布式的治理. 简 ...

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

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

  8. JDK中的SPI机制

    前言 最近学习类加载的过程中,了解到JDK提供给我们的一个可扩展的接口:java.util.ServiceLoader, 之前自己不了解这个机制,甚是惭愧... 什么是SPI SPI全称为(Servi ...

  9. Dubbo SPI机制之一JDK中的SPI

    首先简单阐述下什么是SPI:SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制.目前有不少框架用它来做服务的扩展发现,简单来说,就是一种动态 ...

随机推荐

  1. Java实现蓝桥杯墓地雕塑

    墓地雕塑 问题描述 在一个周长为10000的圆上等距分布着n个雕塑.现在又有m个新雕塑加入(位置可以随意放), 希望所有n+m个雕塑在圆周上均匀分布.这就需要移动其中一些原有的雕塑.要求n个雕塑移动的 ...

  2. Java实现 蓝桥杯VIP 算法提高 超级玛丽

    算法提高 超级玛丽 时间限制:1.0s 内存限制:256.0MB 问题描述 大家都知道"超级玛丽"是一个很善于跳跃的探险家,他的拿手好戏是跳跃,但它一次只能向前跳一步或两步.有一次 ...

  3. 优雅的敲JS代码的几个原则

    一.条件语句        1,使用 Array.includes 来处理多重 || 条件          // ----- 一般 ------ if (fruit == 'apple' || fr ...

  4. 玩转计划任务命令:schtasks

    管理计划任务SCHTASKS /parameter [arguments] 描述:    允许管理员创建.删除.查询.更改.运行和中止本地或远程系统上的计划任务. 参数列表:    /Create   ...

  5. 一个static和面试官扯了一个小时,舌战加强版

    一:背景 1. 讲故事 最近也是奇怪,在社区里看到好几篇文章聊static 的玩法以及怎么拿这个和面试官扯半个小时,有点意思,点进去看都是java版的,这就没意思了,怎么也得有一篇和面试官扯C# 中的 ...

  6. WPF 学习(一)

    一.WPF介绍 WPF全称 Windows Presentation Foundation,干啥用的? 主要是用来制作Windows桌面客户端软件的. .Net平台下制作Windows桌面客户端软件主 ...

  7. tensorflow2.0学习笔记第一章第五节

    1.5简单神经网络实现过程全览

  8. MySQL 8.0 yum安装和配置

    MySQL 8.0 centos7.5 x86_64 一.yum安装 1.先卸载机器和mysql有关的东西,有的安装了mariab-lib,会对安装有干扰,卸载了它. [root@localhost ...

  9. svn版本库的使用

    简单案例: 1.不管在哪个盘下(比如:C盘.D盘等),都先创建文件夹(这里我新建的文件夹是“项目”),创建好了就点击去,如下: 2.在自己新建的文件夹中再新建一个新的文件夹,如下: 3.选中你的文件夹 ...

  10. git提交代码托管平台流程

    首先先安装git git官网 ---- https://git-scm.com/ 下载好傻瓜式安装即可 安装好过后,再桌面任意空白区域右键,看到以下两个选项即为安装成功 一般都用第二个选项也就是 Gi ...