关于spi机制大部分人都很陌生,因为我们在开发过程中很少用到,但是实际上这个机制从我们接触java开始就跟我们如影随形。有些人认为使用java很简单,都是调用第三方依赖包,然后结合自己的业务逻辑就可以了,这个机制就是跟第三方有关。
一、概念
SPI 的全名为 Service Provider Interface,目的hi提供接口,让第三方(服务厂商或扩展框架开发者)提供自定义实现的服务功能。例如,JDBC驱动,可以加载MySQL、Oracle、或者SQL Server等。目前有不少框架用它来做服务的扩张发现。
二、使用规则
通过一张图来看看,用SPI需要遵循哪些规范,因为spi毕竟是JDK的一种标准。
SPI约定:
1、在工程的META-INF/services/目录下,以接口的全限定名作为文件名,文件内容为实现接口的服务类;
2、使用ServiceLoader动态加载META-INF/services下的实现类;
3、接口的实现类需含无参构造函数;(因为类默认包含无参构造函数,如果我们没有重载构造函数所以此处可忽略)
SPI 问题考虑:
1、如果在META-INF/services下有接口实现类,存在多个(例如jar包下面也有相应),系统如何处理?
答:会全部加载,java.util.ServiceLoader在加载资源文件时,已经考虑了这个问题。
2、SPI,和Dubbo等相比,区别在哪里?
答:SPI的目的是提供给各种不同服务相同的访问接口。而Dubbo等微服务是将服务拆分形成功能相对独立的、维护性强的服务。两者出发点并不一致。
三、源码解析
在ServiceLoader中已经默认的加载文件路径
在这里指定文件路径;根据这个路径前缀进行拼接读取相关信息
四、ServiceLoader缺点分析
虽然ServiceLoader也算是使用的延迟加载,但是基本只能通过遍历全部获取,也就是接口的实现类全部加载并实例化一遍。如果你并不想用某些实现类,它也被加载并实例化了,这就造成了浪费。
获取某个实现类的方式不够灵活,只能通过Iterator形式获取,不能根据某个参数来获取对应的实现类
五、demo实例
测试用例:https://github.com/73hulu/corejava