什么是 SPI

SPI是Service Provider Interface的简称,是JDK默认提供的一种将接口和实现类进行分离的机制。这种机制能将接口和实现进行解耦,大大提升系统的可扩展性。

SPI机制约定:当一个Jar包需要提供一个接口的实现类时,这个Jar包需要在META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该Jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。

比如下面的列子,jcl-over-slf4j这个Jar包提供了conmon-logging中LogFactory这个接口的实现。

文件中的内容如下:

# 这里表名具体的实现类是`org.apache.commons.logging.impl.SLF4JLogFactory`这个类
org.apache.commons.logging.impl.SLF4JLogFactory # Axis gets at JCL through its own mechanism as defined by Commons Discovery, which
# in turn follows the instructions found at:
# http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#Service Provider

JDK为了方便查找服务的实现,还提供了一个工具类:java.util.ServiceLoader。

ServiceLoader<Object> loader = ServiceLoader.load(LogFactory);
loader.forEach((item)->{
System.out.println(item);
});

上面代码中使用ServiceLoader遍历使用SPI机制提供的所有LogFactory实现。

应用场景

SPI机制的主要应用有框架扩展和组件的替换等,比如

  • JDBC接口实现类的运行时加载:我们连接具体的数据库是都需要添加相关的Jar包依赖,但是不需要我们再做任何其他配置,只要将Jar包放到classpath下就行了。这是一个最常见的SPI应用场景。
  • 日志门面加载具体的日志实现类:之前的博客中介绍到,jcl和slf4j等只是日志实现类,Log4j和LOgBack才是具体的日志实现。JCL和SLF4J加载日志实现类时也使用了SPI机制,具体请看上面章节中举的列子。
  • Spring中大量使用了SPI:比如对servlet3.0规范对ServletContainerInitializer的实现、自动类型转换Type Conversion SPI(Converter SPI、Formatter SPI)等

自己实现

下面就一步步从定义接口到提供SPI实现类来演示下SPI机制具体的使用方式。

step1:先定义一个接口

public interface SaySomething {

    String say(String name);

}

step2:编写实现类

public class ASaySomething implements SaySomething {
@Override
public String say(String name) {
return "Hi,"+name+", l am A...";
}
}

step3:在resource下添加META-INFO/services目录

添加完这个目录后,添加一个以SaySomething接口的全限定名为名字的文件,这个文件的内容是你要设置的具体实现类。这边我们就设置实现类为上面的ASaySomething

step4:使用SPI机制

public static void main(String[] args) {
ServiceLoader<SaySomething> loader = ServiceLoader.load(SaySomething.class);
loader.forEach(item ->{item.say("csx");});
}

API和SPI的比较

在开发中我们还经常会提到API这个名词,下面也总结下两者的区别:

  • API (Application Programming Interface)在大多数情况下,都是实现方制定接口并完成对接口的实现,调用方仅仅依赖接口调用,且无权选择不同实现。 从使用人员上来说,API 直接被应用开发人员使用。

  • SPI (Service Provider Interface)是调用方来制定接口规范,提供给外部来实现,调用方在调用时则选择自己需要的外部实现。 从使用人员上来说,SPI 被框架扩展人员使用。

优缺点

优点

  • 使用Java SPI机制的优势是实现解耦,使得第三方服务模块的装配控制的逻辑与调用者的业务代码分离,而不是耦合在一起。应用程序可以根据实际业务情况启用框架扩展或替换框架组件

缺点

  • SPI必须先将接口的所有实现类都遍历出来才能最后选择具体使用哪个类。有些不要的类也会被实例化,可能会比较浪费内存。
  • ServiceLoader 并不是线程安全的。

参考

作为一个Java工程师,你应该要知道SPI机制的更多相关文章

  1. 一个Java工程师的入门级Linux命令集

    0.前言    网上介绍linux的命令的文章一大堆,但是大部分都是流于命令介绍,把命令的所有参数都介绍一遍,但是其实在真正的工作中,很多参数都不会用到.本文总结了我自己常用的一些命令,这些命令都比较 ...

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

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

  3. 一文搞懂Java/Spring/Dubbo框架中的SPI机制

    几天前和一位前辈聊起了Spring技术,大佬突然说了SPI,作为一个熟练使用Spring的民工,心中一紧,咱也不敢说不懂,而是在聊完之后赶紧打开了浏览器,开始的学习之路,所以也就有了这篇文章.废话不多 ...

  4. Java工程师如何在1个月内做好面试准备?

    作者:石杉的架构笔记 写在前面 春节长假转眼已过,即将迎来的是一年一度的金三银四跳槽季. 假如你准备在金三银四跳槽的话,那么作为一个Java工程师,应该如何利用1个月的时间,快速的为即将到来的面试进行 ...

  5. 【金三银四跳槽季】Java工程师如何在1个月内做好面试准备?

    目录 一.写在前面 二.技术广度的快速准备 三.技术深度的快速准备 四.基础功底的快速准备 五.下篇预告 一.写在前面 春节长假转眼已过,即将迎来的是一年一度的金三银四跳槽季. 假如你准备在金三银四跳 ...

  6. Java工程师核心书单推荐

    随便打开一个招聘网站,看看对高级Java工程师的技能要求. 抛开其它的经验能力等等,单纯从技术,或者说知识上来讲,可以发现一些共通的地方. Java基础 计算机基础 数据库,SQL/NoSQL 常用开 ...

  7. Java 工程师的学习线路图。

    今天了一个超级好用的工具,思维导图 FreeMind,于是顺道试用了一下,照着画了一张 Java 工程师的学习线路图.

  8. 一个java高级工程师的进阶之路

    宏观方面 一. JAVA.要想成为JAVA(高级)工程师肯定要学习JAVA.一般的程序员或许只需知道一些JAVA的语法结构就可以应付了.但要成为JAVA(高级) 工程师,您要对JAVA做比较深入的研究 ...

  9. 【推荐】Java工程师如何从普通成为大神值得一读

    本文源自 http://www.hollischuang.com/archives/489 一点感悟 java作为一门编程语言,在各类编程语言中作为弄潮儿始终排在前三的位置,这充分肯定了java语言的 ...

随机推荐

  1. EFCore-脚手架Scaffold发生Build Failed问题的终极解决

    大家在使用EntityFrameworkCore的DBFirst的脚手架(Scaffolding)时应该遇到过Build Failed的错误,而没有任何提示,我也遇到过不少次,目前已经完美解决并将排查 ...

  2. Java程序员学习Go语言—之一

    转载:https://www.luozhiyun.com/archives/206 GOPATH 工作空间 GOPATH简单理解成Go语言的工作目录,它的值是一个目录的路径,也可以是多个目录路径,每个 ...

  3. FileZilla 报错“the server's certificate is unknown”

    FileZilla 是非常好用的一款FTP SFTP 管理工具. 但是filezilla会报错“the server's certificate is unknown” 并且会在window中看到以下 ...

  4. halfcheetch win10

    HalfCheetah win10配置 1.使用Anaconda Prompt切到程序目录,执行pip install -r requirements.txt 补充说明: 使用pip与conda命令都 ...

  5. OpenResty学习指南(一)

    我的博客: https://www.luozhiyun.com/archives/217 想要学好 OpenResty,你必须理解下面 8 个重点: 同步非阻塞的编程模式: 不同阶段的作用: LuaJ ...

  6. VirtualBox 虚拟机 从入门到入坑

                                                                                                        ...

  7. 一步一步安装配置Ceph分布式存储集群

    Ceph可以说是当今最流行的分布式存储系统了,本文记录一下安装和配置Ceph的详细步骤. 提前配置工作 从第一个集群节点开始的,然后逐渐加入其它的节点.对于Ceph,我们加入的第一个节点应该是Moni ...

  8. C#系列之基础知识点(一)

    知识点一:VS启动方法 第一种:双击图标 第二种:window+R——调出cmd,输入devenu properties  属性的意思 知识点二:后缀名解释 .sln  解决方案文件:包含整个解决方案 ...

  9. 2020 University Rankings US News(中国)

    2020 University Rankings US News(中国)

  10. supervisor管理tomcat

    操作目的:用supervisor工具管理tomcat服务 配置环境,安装服务,以及多实例 脚本编辑: 前提 机器的opt目录下必须有jdk-8u131-linux-x64_.rpm 以及apache- ...