Service Provider Interface
它是从Java 6开始引入的,是一种基于ClassLoader来发现并加载服务
的机制。
服务发现机制:通过在ClassPath路径下的META-INFO/services文件夹中查找文件,并自动加载文件里所定义的类。
SPI机制可以很好的解决不同框架之间的扩展问题。在java.util.ServiceLoader#load(Class clazz)完成了SPI的实现。
SPI机制能够使接口与具体的实现类解耦,可以根据实际的业务情况启用或替换具体组件。
一个标准的SPI,由3个组件构成,分别是:
在运行时
发现并加载Service Provider。Java SPI的运行流程
Java SPI的三大规范要素:
Service接口的实现类,即Service Provider类,必须具备无参的默认构造方法。因为随后通过反射技术实例化它时,是不带参数的。
示例:
有一家公司(company),它需要连接互联网,它定义一个连接网络的API(network-api),由联通(unicom-network)和电信(telecom-network)来提供网络服务。项目目录如下:
InternetService服务接口定义:
package com.lwy.it;
/**
* 定义了SPI中的Service接口
*/
public interface InternetService {
void connectInternet();
}
telecom-network模块,只有一个实现类:
package com.telecom.network;
import com.lwy.it.InternetService;
/**
* TelecomNetwork 作为 Service Provider类,实现了InternetService接口
*/
public class TelecomNetwork implements InternetService {
@Override
public void connectInternet() {
System.out.println("通过电信网络联网");
}
}
注意:classpath下META-INF/service路径下,定义一个com.lwy.it.InternetService文件
文件名是Service接口的全限定名;文件内容是Service Provider类的全限定名,多个Service Provider用多行表示。
com.telecom.network.TelecomNetwork
unicom-network模块,有两个实现类:
package com.unicom.network;
import com.lwy.it.InternetService;
public class BeijingUnicomNetwork implements InternetService {
@Override
public void connectInternet() {
System.out.println("通过北京联通网络联网");
}
}
package com.unicom.network;
import com.lwy.it.InternetService;
public class UnicomNetwork implements InternetService {
@Override
public void connectInternet() {
System.out.println("通过联通网络联网");
}
}
注意:classpath下META-INF/service路径下com.lwy.it.InternetService文件
com.unicom.network.BeijingUnicomNetwork
com.unicom.network.UnicomNetwork
company模块中定义主方法:
package com.lwy.it;
import java.util.ServiceLoader;
public class Main {
public static void main(String[] args) {
// 使用ServiceLoader发现并加载服务
ServiceLoader<InternetService> loader = ServiceLoader.load(InternetService.class);
// 面向Service接口编程
for (InternetService provider : loader) {
provider.connectInternet();
}
}
}
通过分别引入maven依赖不同,打印的结果也不同。
<dependency>
<groupId>com.lwy.itgroupId>
<artifactId>unicom-networkartifactId>
<version>1.0-SNAPSHOTversion>
dependency>
<dependency>
<groupId>com.lwy.itgroupId>
<artifactId>telecom-networkartifactId>
<version>1.0-SNAPSHOTversion>
dependency>