概述
什么是SPI
软件很大程度是真实世界的反映,思想、模式都能在真实事物找到影子。这不难理解,因为不管是真实事物还是软件都是由人类创造,都是朝着高效、低成本方向发展,难免相互借鉴。SPI也是如此,SPI全称Service Provider Interface。本质就是上层软件制定所需模块的接口规范,然后基于这个规范搭建上层建筑,至于模块谁来开发实现并不关心,反正厂商按照接口规范做出来就好。好比汽车厂商开发一款新型汽车,轮胎不要他生产,他只要告诉轮胎厂商这款车要用195/55/R16 85V 规格的轮胎,轮胎厂商按照这个标准生产即可。
SPI的应用比较常见,比如说 (1) jdbc驱动,如果针对具体的数据库开发软件,换数据库将是灾难级调整。所以业务面向jdbc接口规范开发,利用SPI自动发现接口实现类将极大提高软件的扩展性;(2) 之前写过的ServletContainerInitializer,servlet容器用SPI发现spring-web包中的SpringServletContainerInitializer从而启动初始化应用;(3) 此外,还有日志框架、validation(hibernator-validator)也是基于SPI机制发现具体的服务实现。
SPI机制原理
SPI的核心是java.util.ServiceLoader。ServiceLoader大致的过程是在classpath*:META-INF/services/目录下查找配置文件(名称是接口的全路径类名),这个文件里面每一行就是实现类的全路径类名,然后用当前线程的classloader加载实现类。具体实现可以看看jdk源码:
public final class ServiceLoader<S> implements Iterable<S>{
//查找的目录
private static final String PREFIX = "META-INF/services/";
......
//内部类 具体的查找的实现
private class LazyIterator implements Iterator<S>{
......
private boolean hasNextService() {
if (nextName != null) {
return true;
}
if (configs == null) {
try {
String fullName = PREFIX + service.getName();
if (loader == null)
configs = ClassLoader.getSystemResources(fullName);
else
configs = loader.getResources(fullName);
} catch (IOException x) {
fail(service, "Error locating configuration files", x);
}
}
while ((pending == null) || !pending.hasNext()) {
if (!configs.hasMoreElements()) {
return false;
}
pending = parse(service, configs.nextElement());
}
nextName = pending.next();
return true;
}
......
}
......
}
spi demo程序
整一个demo程序跑一跑,否则太干巴巴的了,demo程序尽量简单,只是打个日志,实现2个具体的实现类。
首先,定一个接口LogPrint
public interface LogPrint {
//打印日志
void print(String message);
}
其次,创建2个实现类LogPrintImplA、LogPrintImplB
package com.focuse.jdkdemo.spi;
public class LogPrintImplA implements LogPrint {
@Override
public void print(String message) {
System.out.println("LogPrinterA: " + message);
}
}
package com.focuse.jdkdemo.spi;
public class LogPrintImplB implements LogPrint {
@Override
public void print(String message) {
System.out.println("LogPrinterB: " + message);
}
}
第三步,在目录META-INF/services下创建文件com.focuse.jdkdemo.spi.LogPrint,文件内容2行。
最后,用ServiceLoader加载实现类,并运行程序
package com.focuse.jdkdemo.spi;
import java.util.Iterator;
import java.util.ServiceLoader;
/**
* @author :focuse
* @date :Created in 2020/2/16 上午11:10
* @description:
* @modified By:
*/
public class SPIDemo {
public static void main(String[] args) {
ServiceLoader<LogPrint> loader = ServiceLoader.load(LogPrint.class);
Iterator<LogPrint> it = loader.iterator();
while (it.hasNext()) {
it.next().print("hello spi!");
}
}
}
ps: 为了让demo程序简单,就没有用jar引用的形式,而是直接在一个工程里面完成所有的事情
最后
以上就是漂亮板栗为你收集整理的java原生SPI机制详解什么是SPI SPI机制原理spi demo程序的全部内容,希望文章能够帮你解决java原生SPI机制详解什么是SPI SPI机制原理spi demo程序所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复