Java SPI机制实践
1. SPI机制
SPI(Service Provider Interface
),是Java自带的服务加载及发现机制,便于第三方对服务进行实现或扩展。
服务,通常用接口或抽象类来定义,实现类也可以但不推荐使用。
服务提供者,即服务的具体实现,通常是一个实现类,当然通常也可以是一个第三方独立服务的代理。
服务加载及发现机制,定义好服务及提供者之后,在META-INF/services
下新建一个文件,以服务接口或抽象类的全限定名命名。文件中每一行代表一个服务提供者,写实现类的全限定名,以#
号代表注释。文件定义好后,使用ServiceLoader
工具类进行加载和实例化。
2. SPI实践
以Hash
算法为例,先定义服务如下:
public interface Hash {
public String hash(String value);
}
Java自带的及murur
的服务实现如下:
public class JavaHash implements Hash {
public JavaHash() {
}
@Override
public String hash(String value) {
Objects.requireNonNull(value, "value cann't be null");
int hash = value.hashCode();
return Integer.toHexString(hash);
}
}
public final class MurmurHash implements Hash {
public MurmurHash() {
}
@Override
public String hash(String value) {
Objects.requireNonNull(value, "value cann't be null");
byte[] bytes = value.getBytes();
int hash = this.hash(bytes, bytes.length, -1);
return Integer.toHexString(hash);
}
private int hash(byte[] data, int length, int seed) {
int h = seed ^ length;
……
return h;
}
}
在META-INF/services
下新建文件com.github.myron.spi.Hash
,内容如下:
# Hash Service Provider
com.github.myron.spi.JavaHash
com.github.myron.spi.MurmurHash
服务加载及使用示例如下:
public static void main(String[] args) {
ServiceLoader<Hash> hashServices = ServiceLoader.load(Hash.class);
String value = "A simple service-provider loading facility.";
for (Hash hash : hashServices) {
String result = hash.hash(value);
System.out.println(hash.getClass().getSimpleName() + ": " + result);
}
}
运行结果如下:
JavaHash: 60fddbf
MurmurHash: a44a39a
1、服务实现类必须有无参构造子,
ServiceLoader
中直接使用Class.newInstance()
进行实例化。
2、在Marven项目中,META-INF/services
目录需放在在src/main/resources
下。
3. SPI应用场景
SPI
机制,在JDK中有多个应用场景,如Java Sound
1、Java File Systems
、Java Image I/O
等。
服务治理开源框架Dubbo
2,也参考SPI
实现了自己的扩展机制,方便使用者定义自己的Protocol、Filter等。
总体而言,SPI
适用于在框架或工具包中预留扩展点,方便第三方实现自定义的服务。
wikipedia: Service provider interface
Java: ServiceLoader
Java spi机制浅谈