目录
API(Application Programming Interface)
SPI(Service provider interface)
近期看了很多开源组件的源码,发现很多地方地方用到了 spi 的功能,开始思考 spi 与 api 的区别
发现 spi 侧重于抽象层次的概念,目前接触到的就是 java 里大量用到了这个,通过定义的接口来抽象通用的功能,然而 api 是不限编程语言限制的。例如自己写的很多调用方法(对应其他语言里的函数)。
API(Application Programming Interface)
应用程序编程接口,日常开发中大部分用的是这个
api,就是服务提供方定义的规范,调用方(开发者)必须遵守的。例如开发中使用了java语言以及一些第三方组件,规范是人家语言的开发者定义的,自己需要按照文档要求来调用对应 api 来完成自己想要的功能。
SPI(Service provider interface)
可以参见之前自己写的一篇文章中关于 spi 的讲解
https://blog.csdn.net/zlpzlpzyd/article/details/133899501
官网介绍
https://docs.oracle.com/javase%2Ftutorial%2F/sound/SPI-intro.html
通过 java.util.ServiceLoader 加载在 classpath 下 META-INF/services 中所有的文件中对应的类
看到一篇文章的讲解,从服务提供方与服务调用方来解释这个问题,感觉有道理
spi,是服务调用方定义的规范。具体例子有
注册中心与服务发现
spring-cloud-commons 就通过接口的形式定义了一套,其他的注册中心例如 eureka、consul、nacos 实现了对应的接口。
通过跟踪源码,发现未通过spi实现。即 classpath 下无 META-INF/services 相关目录。
日志组件slf4j
slf4j通过门面模式整合了各种日志,例如 logback、log4j2 等其他日志。
通过跟踪源码,发现未通过spi实现。即 classpath 下无 META-INF/services 相关目录。
servlet规范
对应的 servlet 容器有 tomcat、undertow、jetty 等。
通过跟踪源码,发现未通过spi实现。即 classpath 下无 META-INF/services 相关目录。
jdbc 规范
对应的各个数据库厂商开发的各种数据库驱动。
mysql 8 驱动针对 java.sql.Driver 的实现类为
com.mysql.cj.jdbc.Driver
druid 驱动针对 java.sql.Driver 的实现类为
com.alibaba.druid.proxy.DruidDriver
com.alibaba.druid.mock.MockDriver
上面这些 spi 就是跟 java 官方(除了jdbc规范在 java 官方自带 api里)无关了,一些民间组织根据市场上现有的一些组件进行功能抽象后通过一个抽象层次的接口来进行调用具体实现。
使用 spi 符合面向接口编程的理念,通过定义的接口规范来进行逻辑处理,降低程序之间的耦合。
有点类似于 spring boot 里的 @ConditionalXXX 注解。
总结下来,区别就是编程规范话语权在谁手里的问题。
api 的话语权在别人那里(对应编程语言官方的api和操作系统api),自己不能改,必须遵守别人的写法。
spi 的话语权在民间组织里,自己根据一些通用组件功能可以抽象出来一个规范(一般是建立在 javax包下通过子包名来指定具体的用途),只要别人愿意遵守这个即可。
参考链接
https://blog.csdn.net/qq_49662572/article/details/128435720
https://blog.csdn.net/JDDTechTalk/article/details/132764476
https://blog.csdn.net/weixin_59244784/article/details/130523170