SPI的全名为Service Provider Interface.普通开发人员可能不熟悉,因为这个是针对厂商或者插件的。在java.util.ServiceLoader的文档里有比较详细的介绍。
简单来说就是通过配置文件指定接口的实现类。
当我们开发一套框架、一套机制、一个插件或一套API时候,如果需要第三方的服务支持,可以直接写死到代码里面,但这种方式耦合太强,不利于切换到其它服务,好的方法是写一个配置文件指定服务的实现方,幸运的是java的spi机制已经帮我们做好了,示例用法如下:
一个接口:
1. package testws;
2
3. public interface TestEJB {
4. void test(String data) throws Exception;
5. void test0(String data) throws Exception;
6. }
第一个实现类:
1. package testws;
3. public class MyTest implements TestEJB {
4. public void test(String data) throws Exception {
5. System.out.println("my test:" + data);
6. }
8. public void test0(String data) throws Exception {
9. System.out.println("test0:" + data);
10. }
11. }
第二个实现类:
1. package testws;
3. public class MyTest2 implements TestEJB {
4. public void test(String data) throws Exception {
5. System.out.println("my test2222:" + data);
6. }
8. public void test0(String data) throws Exception {
9. System.out.println("test02222222:" + data);
10. }
11. }
建立 META-INF 文件夹,在其里面建立 services 文件夹,在services文件夹下建立一个文件,名称为我们需要实现的服务的全类名,即:testws.TestEJB
文件testws.TestEJB的内容如下:(PS:如果我们只需要一个实现类,下面可以只写一个,每一个实现类占一行)
testws.MyTest
testws.MyTest2
最后一个步骤:将三个java类和META-INF 文件夹打包到一个jar中,就可以使用了,使用方式:
public class TestSPI {
public static void main(String[] args) {
ServiceLoader<TestEJB> loadedImpl = ServiceLoader.load(TestEJB.class);
for (TestEJB testEJB : loadedImpl) {
System.out.println(testEJB.getClass());
try {
testEJB.test("a");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
打印如下:
1. class testws.MyTest
2. my test:a
3. class testws.MyTest2
4. my test2222:a