什么是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. Android中如何使用GridView

    首先在主XML中放入Grid View控件 取好id private GridView gv1; private int[] icon = {R.drawable.cat, R.drawable.co ...

  2. Java实现 洛谷 P1023 税收与补贴问题

    import java.util.Scanner; public class Main { public static void main(String[] args){ Scanner in = n ...

  3. Java实现台阶问题

    1 问题描述 一个台阶总共有n级,如果一次可以跳1级,也可以跳2级,求总共有多少种跳法. 2 解决方案 2.1 递归法 如果整个台阶只有1级,则显然只有一种跳法.如果台阶有2级,则有两种跳法:一种是分 ...

  4. Java实现有理数的循环节

    1/7 = 0.142857142- 是个无限循环小数. 任何有理数都可以表示为无限循环小数的形式. 本题目要求即是:给出一个数字的循环小数表示法. 例如: 输入: 1,5 则输出: 0.2 输入: ...

  5. java实现第五届蓝桥杯锦标赛

    锦标赛 这题小编能力有限,还望大佬解决 题目描述 如果要在n个数据中挑选出第一大和第二大的数据(要求输出数据所在位置和值),使用什么方法比较的次数最少?我们可以从体育锦标赛中受到启发. 如图[1.pn ...

  6. QPS、TPS、并发用户数、吞吐量关系

    1.QPS QPS Queries Per Second  是每秒查询率 ,是一台服务器每秒能够相应的查询次数,是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准, 即每秒的响应请求数,也即 ...

  7. webpack+vue+.vue组件模板文件 所需要的包

    {  "name": "webpack-study02",  "version": "1.0.0",  "de ...

  8. iOS-自定义Model转场动画-仿酷我音乐播放器效果

    周末,闲来无事,仿写了酷我音乐播放器效果: 效果图如下: 实现思路: 1.实现手势处理视图旋转 2.自定义Model动画: 1.手势是利用了一个UIPanGestureRecognizer手势: 注意 ...

  9. MySQL数据库离线包安装与注册

    本文主要介绍了MySQL数据库的离线安装和将MySQL服务注册为Windows应用服务的主要步骤. 1.下在安装程序包 MySQL Community Server 5.6.15 官方下载地址http ...

  10. SQL--SQL详解(DDL,DML,DQL,DCL)

    SQL--SQL详解(DDL,DML,DQL,DCL) 博客说明 文章所涉及的资料来自互联网整理和个人总结,意在于个人学习和经验汇总,如有什么地方侵权,请联系本人删除,谢谢! 什么是SQL? Stru ...