- 看到公司的项目代码中,在META-INF下service中定义了一些文件。文件名都是以全限定类名的方式命名的,而且没每个文件里的内容也是一堆全限定类名的值。搞不懂这些是什么用途,遂百度了一下
- 看到了一篇介绍java中spi的博客链接,该博客中对于java的spi机制做了一些介绍,博客链接附上:点击打开链接
- 传统的应用中,我们对于一个接口有多个实现类。每一个实现类我们在使用的时候,都是动态去调用的。如果是基于java的spi,我们可以通过在工程的META-INF的service文件夹下创建基于接口的全限定类名的文件,文件内容是对于这个接口提供的多个实现类,内容的格式是一个实现类的全限定类名为一行。
下面通过一个具体的案例来说明spi的实现方式(官方的文档里,对于serviceloader的讲解里有一个具体的例子。):
- 首先我们定义一个接口类 com.example.CodeSet,该类中定义了一组针对于某种协议的编码解码的接口方法:
public abstract Encoder getEncoder(String encodingName); public abstract Decoder getDecoder(String encodingName);
每个方法都根据提供的编码返回一个特定的对象,如果该方法不支持该编码格式则返回null -
我们再定义一个实现类com.example.impl.StandardCodecs,它实现了接口CodeSet中定义的方法
-
我们在工程中创建如下格式的文件META-INF/services/com.example.CodecSet,其中com.example.CodecSet是一个文件名(该文件是基于接口的全限定类名命名的)
-
我们在CodeSet类,初始化的时候创建和保存一个单一的service instance:
private static ServiceLoader<CodecSet> codecSetLoader = ServiceLoader.load(CodecSet.class);
-
定义了一个静态工厂方法,根据提供的编码名字,去迭代每一个方法的具体实现者,返回相关的编码和解码对象:
至此对于spi的一个实现的,就大功告成啦!!!public static Encoder getEncoder(String encodingName) { for (CodecSet cp : codecSetLoader) { Encoder enc = cp.getEncoder(encodingName); if (enc != null) return enc; } return null; }
附上项目结构: