1.SPI介绍
SPI的全名是Service Provider Interface
, JDK 内置的一种服务提供机制,用于提升接口的可扩展性,其最终的目的是用于模块之间的解耦,减少相互依赖。
2.SPI的用法
- 服务的提供方对调用方的接口提供了一种实现, 在jar包中resource的
META-INF/services
目录下创建一个接口的全限定名的文件,该文件的内容是是实现类的全限定名; - 在主程序中使用java的util包中的
ServiceLoader
加载该接口从而获取该实现类; - 实现类要带一个无参构造;
3.SPI的简单Demo
SPI 的Demo结构
SPI 的Demo代码
//定义接口
public interface PayMethod {
void getPayMethod();
}
//两个实现类
public class AliPayMethod implements PayMethod {
@Override
public void getPayMethod() {
System.out.println("ali pay");
}
}
public class WechatPayMethod implements PayMethod {
@Override
public void getPayMethod() {
System.out.println("wechat pay");
}
}
//主程序
public class SPIDemo {
public static void main(String[] args) {
ServiceLoader<PayMethod> payMethods = ServiceLoader.load(PayMethod.class);
Iterator<PayMethod> iterable = payMethods.iterator();
while (iterable.hasNext()){
System.out.println(iterable.next());
}
}
}
//文件
com.dev.impl.WechatPayMethod
com.dev.impl.AliPayMethod
上述输出是两个实现类的对象地址。如果你是maven项目的话,请使用jar工程,POM工程是不生效的。
4.SPI的实际应用
- 数据驱动加载。JDBC4.0
private static void loadInitialDrivers() {
String drivers;
try {
drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty("jdbc.drivers");
}
});
} catch (Exception ex) {
drivers = null;
}
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator();
try{
while(driversIterator.hasNext()) {
driversIterator.next();
}
} catch(Throwable t) {
// Do nothing
}
return null;
}
});
......
}
- servlet 3.0 提供自定义组件的初始化工
就servlet 3.0自定义组件的初始化而言,Spring官网也是通过要求实现WebApplicationInitializer
来减少web.xml的配置。点击此处
Servlet初始化自定义组件过程:
- 在启动web容器时,会自动扫描META-INF/services目录下的文件,并将文件中的类实例化;
- Spring通过使用
SpringServletContainerInitializer
实现ServletContainerInitializer
, 从而在容器启动时会执行onStartup
方法; - Spring此时为了扩展性重新定义了一个
WebApplicationInitializer
的接口,@HandlesTypes
会将WebApplicationInitializer
的所有实现类作为一个set参数传入; SpringServletContainerInitializer
会执行WebApplicationInitializer
所有的实现类中onStartup
方法进而实现开发者自定义组件的初始化;
(上述图片来源于网络,侵删)