什么是SPI
SPI ,全称为 Service Provider Interface,是一种服务发现机制。它通过在ClassPath路径下的META-INF/services文件夹查找文件,自动加载文件里所定义的类。
SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。正因此特性,我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能。SPI 机制在第三方框架中也有所应用,比如 Dubbo 就是通过 SPI 机制加载所有的组件。不过,Dubbo 并未使用 Java 原生的 SPI 机制,而是对其进行了增强,使其能够更好的满足需求。在 Dubbo 中,SPI 是一个非常重要的模块。基于 SPI,我们可以很容易的对 Dubbo 进行拓展。如果大家想要学习 Dubbo 的源码,SPI 机制务必弄懂。
spi的工作原理
就是ClassPath路径下的META-INF/services文件夹中, 以接口的全限定名来命名文件名,文件里面写该接口的实现。然后再资源加载的方式,读取文件的内容(接口实现的全限定名), 然后再去加载类。
spi可以很灵活的让接口和实现分离, 让api提供者只提供接口, 第三方来实现。
SPI的作用
其实我们平时用的框架很多都是使用了SPI机制,我们都知道开源框架的扩展性很高,为什么框架的扩展性都很高呢,其中一个重要原因就是利用了SPI机制,SPI让框架的扩展成为了可能,我们平时在进行模块化设计时,只有深入理解了SPI机制,才能更好的设计出符合可插拔原则的模块。
SPI如何使用
那么现在有这样的场景:当我的项目里面有什么支付模块我就使用什么样的支付模块,比如说有支付宝支付模块就选择支付宝、有微信支付模块我就选择微信支付、同时有多个的时候,我默认选择第一个,此时我们就可以使用SPI,先看下如何使用。
1、创建META-INF/services文件夹,然后创建一个以Pay接口全限定名为名字的文件
2、在文件中编写想要实现哪个Pay的实现类(AliPay,WechatPay,BankCardPay),注意也要是全限定名。
3、获取Pay并调用
获取并调用的逻辑,我就修改下上面的策略模式中的Context的invokerStrategy方法,这里假设默认使用第一个
public void invokeStrategy(){
ServiceLoader<Pay> payServiceLoader = ServiceLoader.load(Pay.class);
Iterator<Pay> iterator = payServiceLoader.iterator();
if (iterator.hasNext()){
iterator.next().pay();
}
}
本文是对spl的原理机制以及简单的使用。这对组件化技术核心点有着关键作用,更多的进阶技术可以参考《Android核心技术进阶手册》点击可查看里面详细的内容板块。
SPI的应用场景
其实SPI的应用场景非常多,比如我们在进行模块化拆分时,有技术负责人主导模块拆分和接口定义,由小组成员具体实现服务。
在实际业务开发中,比如芯选商城用户支付,项目里面有什么支付模块我就使用什么样的支付模块,比如说有支付宝支付模块就选择支付宝、有微信支付模块我就选择微信支付、同时有多个的时候,我默认选择第一。