本文参考:SPI机制
SPI(Service Provider Interface),是JDK内置的一种服务提供发现机制,可以用来启动框架扩展和替换组件,主要是被框架的开发人员使用,比如 java.sql.Driver接口,其他不同厂商可以针对统一接口做出不同的实现,MySQL和PostgreSQL都有不同的实现提供给用户,而 Java 的SPI机制可以为某个接口寻找服务发现。Java中SPI机制主要思想是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要,其核心思想就是解耦。
当程序的提供者提供了一种接口的实现之后,需要在classPath
下的 META-INF/services/
目录中创建一个以服务接口命名的文件,这个文件里的内容就是这个接口的具体的实现类。当其他的程序需要这个服务的时候,就可以通过查找这个jar包(一般都是以jar包做依赖)的META-INF/services/
中的配置文件,配置文件中有接口的具体的实现类名,可以根据这个类名进行加载实例化,就可以使用该服务了。JDK中查找服务的实现的工具类是:java.util.ServiceLoader
SPI机制的应用?
-
SPI机制 - JDBC DriverManager
在JDBC4.0之前,在开发有连接数据库的时候,通常会用 Class.forName(“com.mysql.jdbc.Driver”) 这句先加载数据库相关的驱动,然后再进行获取连接等的操作。而JDBC4.0之后不需要用 Class.forName(“com.mysql.jdbc.Driver”) 来加载驱动,直接获取连接就可以了,现在这种方式就是使用了 Java的SPI扩展机制来实现。
-
JDBC接口定义
首先在 Java中定义了接口
java.sql.Driver
,但是并没有具体的实现,具体的实现都是由不同厂商来提供的 -
MySQL实现
在 MySQL的 jar包 mysql-connector-java:8.0.22
中,可以找到 META-INF/services/
目录,该目录下会有一个名字为 java.sql.Driver
的文件,文件内容是 com.mysql.cj.jdbc.Driver
,这里面的内容就是针对 Java中定义的接口的实现。
下面测试一个 demo:
定义一个存储方式接口 SPIStoreInterface
/**
* SPI interface
*/
public interface SPIStoreInterface {
String storeMethod(String method);
}
编写两个实现类 CloudStore、LocalStore
CloudStore:
/**
* use Network store method
*/
public class CloudStore implements SPIStoreInterface {
private static final Logger LOG = LoggerFactory.getLogger(CloudStore.class);
@Override
public String storeMethod(String method) {
LOG.info("使用云存储");
return "network store";
}
}
LocalStore:
/**
* use Local store method
*/
public class LocalStore implements SPIStoreInterface {
private static final Logger LOG = LoggerFactory.getLogger(LocalStore.class);
@Override
public String storeMethod(String method) {
LOG.info("使用本地存储");
return "network store";
}
}
编写SPI services文件
进行测试,验证效果
public class TestSPI {
public static void main(String[] args) {
ServiceLoader<SPIStoreInterface> loader = ServiceLoader.load(SPIStoreInterface.class);
Iterator<SPIStoreInterface> iterator = loader.iterator();
while (iterator.hasNext()) {
SPIStoreInterface next = iterator.next();
next.storeMethod("spi test success");
}
}
}
result: