概述
SPI全称Service Provider Interface,即服务提供者接口,是Java的一种扩展机制。通过该机制,Java应用可以发现和使用对接口的外部实现。这些由外部服务(通常是一个jar包,包含具体的实现类)提供实现的接口即被称为SPI,该外部服务即被称为Service Provider(服务提供者).
Service Provider提供的jar包应位于classpath中,需提供一个配置文件,放在jar包的META-INF/services目录下,该配置文件名称为SPI的全限定接口名,文件中列出一个至多个具体实现类的全限定类名,每行一个。
ServiceLoader类负责发现和加载Service Provider提供的具体实现类。
举例说明
Java中的数据库连接驱动接口 java.sql.Driver,是一个SPI,不同的数据库厂商会提供各自的实现,例如Oracle提供的实现包含在ojdbc8包中,如下图,该包的META-INF/services目录下包含了一个名为java.sql.Driver的文件,文件中的内容为接口的具体实现类oracle.jdbc.OracleDriver
在将该jar包添加到classpath以后,通过ServiceLoader就可以发现并加载OracleDriver了
ServiceLoader的使用
ServiceLoader类用于发现和加载SPI的实现类。其核心是一个LinkedHashMap属性(用来缓存SPI的实现类,key为实现类的全限定类名,value为实现类对象),和一个LazyIterator内部类(用来遍历和加载实现类)。ServiceLoader采用懒加载的方式,即调用load方法以后,并不会马上实例化所有的实现类,而是在通过iterator进行遍历的时候才会通过Class.forName和newInstance进行实例化。
load静态方法的ClassLoader参数可选,不传时,默认使用当前线程的ClassLoader. load方法每次调用都会返回一个新的ServiceLoader对象(包含新的LazyIterator对象)
reload实例方法会清空当前缓存,即LinkedHashMap,并创建新的LazyIterator对象,则可重新遍历和实例化
参考文献
https://www.baeldung.com/java-spi
https://reflectoring.io/service-provider-interface/