Java 程序员在日常工作中经常会听到 SPI,而且很多框架都使用了 SPI 的技术,那么问题来了,到底什么是 SPI 呢?今天阿粉就带大家好好了解一下 SPI。
SPI 概念
SPI 全称是 Service Provider Interface,是一种 JDK 内置的动态加载实现扩展点的机制,通过 SPI 技术我们可以动态获取接口的实现类,不用自己来创建。
这里提到了接口和实现类,那么 SPI 技术上具体有哪些技术细节呢?
接口:需要有一个功能接口;
实现类:接口只是规范,具体的执行需要有实现类才行,所以不可缺少的需要有实现类;
配置文件:要实现 SPI 机制,必须有一个与接口同名的文件存放于类路径下面的 META-INF/services 文件夹中,并且文件中的每一行的内容都是一个实现类的全路径;
类加载器 ServiceLoader:JDK 内置的一个类加载器,用于加载配置文件中的实现类;
举个栗子
上面说了 SPI 的几个概念,接下来阿粉就通过一个栗子来带大家感受一下具体的用法。
第一步
创建一个接口,这里我们创建一个解压缩的接口,其中定义了压缩和解压的两个方法。
package com.example.demo.spi;
/**
- Function:
- Author:@author ziyou
- Date:2022-10-08 21:31
- Desc:无
*/
public interface Compresser {
byte[] compress(byte[] bytes);
byte[] decompress(byte[] bytes);
}
复制代码
第二步
再写两个对应的实现类,分别是 GzipCompresser.java 和 WinRarCompresser.java 代码如下
package com.example.demo.spi.impl;
import com.example.demo.spi.Compresser;
import java.nio.charset.StandardCharsets;
/**
- Function:
- Author:@author ziyou
- Date:2022-10-08 21:33
- Desc:无
*/
public class GzipCompresser implements Compresser {
@Override
public byte[] compress(byte[] bytes) {
return"compress by Gzip".getBytes(StandardCharsets.UTF_8);
}
@Override
public byte[] decompress(byte[] bytes) {
return "decompress by Gzip".getBytes(StandardCharsets.UTF_8);
}
}
复制代码
package com.example.demo.spi.impl;
import com.example.demo.spi.Compresser;
import java.nio.charset.StandardCharsets;
/**
- Function:
- Author:@author ziyou
- Date:2022-10-08 21:33
- Desc:无
*/
public class WinRarCompresser implements Compresser {
@Override
public byte[] compress(byte[] bytes) {
return "compress by WinRar".getBytes(StandardCharsets.UTF_8);
}
@Override
public byte[] decompress(byte[] bytes) {
return "decompress by WinRar".getBytes(StandardCharsets.UTF_8);
}
}
复制代码
第三步
创建配置文件,我们接着在 resources 目录下创建一个名为 META-INF/services 的文件夹,在其中创建一个名为 com.example.demo.spi.Compresser 的文件,其中的内容如下:
com.example.demo.spi.impl.WinRarCompresser
com.example.demo.spi.impl.GzipCompresser
复制代码
注意该文件的名称必须是接口的全路径,文件里面的内容每一行都是一个实现类的全路径,多个实现类就写在多行里面,效果如下。
第四步
有了上面的接口,实现类和配置文件,接下来我们就可以使用 ServiceLoader 动态加载实现类,来实现 SPI 技术了,如下所示:
package com.example.demo;
import com.example.demo.spi.Compresser;
import java.nio.charset.StandardCharsets;
import java.util.ServiceLoader;
public class TestSPI {
public static void main(String[] args) {
ServiceLoader<Compresser> compressers = ServiceLoader.load(Compresser.class);
for (Compresser compresser : compressers) {
System.out.println(compresser.getClass());
}
}
}