什么是 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. 跨源请求cors和jsonp

    0.产生跨域的原因 浏览器的同源策略 什么是浏览器的同源策略? src开发 ajax禁止 解决方法 jsonp 通过src绕过浏览器的同源策略 缺点:只发送GET请求 cors 通过设置相应头 分类 ...

  2. newSQL 到底是什么?

    数据库发展至今已经有3代了: SQL,传统关系型数据库,例如 MySQL noSQL,例如 MongoDB newSQL SQL 的问题 互联网在本世纪初开始迅速发展,互联网应用的用户规模.数据量都越 ...

  3. 如何学习理解Redux Middleware

    Redux中的middleware其实就像是给你提供一个在action发出到实际reducer执行之前处理一些事情的机会.可以允许我们添加自己的逻辑在这段当中.它提供的是位于 action 被发起之后 ...

  4. Elasticsearch系列---结构化搜索

    概要 结构化搜索针对日期.时间.数字等结构化数据的搜索,它们有自己的格式,我们可以对它们进行范围,比较大小等逻辑操作,这些逻辑操作得到的结果非黑即白,要么符合条件在结果集里,要么不符合条件在结果集之外 ...

  5. 机器学习环境配置系列五之keras2

    keras一个大坑就是配置文件的问题,网上会给很多的误导,让我走了很多弯路. 1.安装keras2 conda install keras 2.环境配置 echo ‘{ "epsilon&q ...

  6. HGE引擎改进——2014/2/18 和 2014/2/27

    2014/2/18 更新 hgehelper库:增加hgeSkeleton类,该类用于播放骨骼动画 增加工具骨骼动画编辑器(AnimationEd),该工具用于骨骼动画的编辑 2014/2/27 更新 ...

  7. HTML超全笔记

    HTML概述 概念:是最基础的网页开发语言 Hyper Text Markup Language 超文本标记语言 超文本: 超文本是用超链接的方法,将各种不同空间的文字信息组织在一起的网状文本. 标记 ...

  8. 基于playcanvas的3d模型展示

    1.使用基于playcanvas的离线编辑器制作模型效果 2.使用基于playcanvas的开发包读取编辑好的3d模型进行在线3d展示 效果如下:

  9. PlayCanvas PBR材质shader代码分析(vertex shader)

    顶点shader主要对顶点坐标变换,将顶点坐标从local->world->view->clip 空间变换 local空间:模型物体坐标系 world空间:世界空间坐标系 view空 ...

  10. 吉哥系列故事——恨7不成妻(数位dp)

    吉哥系列故事--恨7不成妻 传送门 Problem Description 单身! 依然单身! 吉哥依然单身! DS级码农吉哥依然单身! 所以,他生平最恨情人节,不管是214还是77,他都讨厌! 吉哥 ...