JAVA - SPI理解
先来看看我们平时使用的比较多的api:实现方提供了接口和实现,我们可以调用某些实现类的功能,实现方的接口和代码通常会放在一个包中
那如果接口属于调用方时,我们就称为其为SPI,即一种为某个接口寻找服务实现的一种机制,举个简单的例子,jdbc连接数据库,第三方厂商根据一个统一的规范(jdbc.driver)实现各自的逻辑,所以当你使用jdbc的时候仅仅需要引入不同的第三方厂商的spi接口服务即可,Mysql的则是com.mysql.jdbc.Drive,Oracle则是oracle.jdbc.driver.OracleDriver。
spi的约定:
当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件,该文件里就是实现该服务接口的具体实现类。当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。
基于这样的一个约定,就能很好的找到服务接口的实现类,而不需要在代码里指定,jdk提供服务实现类查找的工具类:java.util.ServiceLoader
SPI 简单示例:
- 项目结构
- spi-api 定义的接口,针对第三方厂商定义的统一规范,只有接口
- spi-doctor 接口实现,即第三方厂商针对接口的不同实现之一
- spi-teacher 接口实现,即第三方厂商针对接口的不同实现之一
- spi-core 提供给用户使用的文件,用户使用的时候引入对应厂商的jar即可
- api-spi
public interface PeopleAPI {
public void profession();
}
- spi-doctor
接口实现:
public class Doctor implements PeopleAPI {
public void profession() {
System.out.println("我是一名医生");
}
}
在resource下新建目录META-INF/services,新建文件:com.PeopleAPI 写入具体的实现类名
com.test.Doctor
pom.xml
<dependencies>
<dependency>
<groupId>z</groupId>
<artifactId>spi-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
- spi-teacher
类似spi-doctor一样的做法
public class Teacher implements PeopleAPI {
public void profession() {
System.out.println("我是一名老师");
}
}
META-INF/services/com.PeopleAPI
com.test.Teacher
pom.xml
<dependencies>
<dependency>
<groupId>z</groupId>
<artifactId>spi-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
- spi-core
public class PeopleCore {
public void getPeopleCore (){
ServiceLoader<PeopleAPI> serviceLoader = ServiceLoader.load(PeopleAPI.class);
Iterator<PeopleAPI> peoples = serviceLoader.iterator();
boolean flag = true;
while (peoples.hasNext()){
flag = false;
PeopleAPI peopleAPI = peoples.next();
peopleAPI.profession();
}
if(flag){
throw new RuntimeException("没找到具体实现类");
}
}
}
pom.xml
<dependency>
<groupId>z</groupId>
<artifactId>spi-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>z</groupId>
<artifactId>spi-teacher</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- 想用哪个只需要替换就可-->
<!-- <dependency>-->
<!-- <groupId>z</groupId>-->
<!-- <artifactId>spi-doctor</artifactId>-->
<!-- <version>1.0-SNAPSHOT</version>-->
<!-- </dependency>-->
test
@Test
public void test1(){
PeopleCore peopleCore = new PeopleCore();
peopleCore.getPeopleCore();
}