参考文档:Java SPI(Service Provider Interface)简介(http://blog.csdn.net/top_code/article/details/51934459)
一、SPI 是什么?
SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制。
二、SPI如何使用?
一个服务(Service)通常指的是已知的接口或者抽象类,服务提供方就是对这个接口或者抽象类的实现,然后按照SPI 标准存放到资源路径META-INF/services目录下,文件的命名为该服务接口的全限定名。如有一个服务接口:
package com.ricky.codelab.spi;
public interface DemoService {
public String sayHi(String msg);
}
其实现类为:
package com.ricky.codelab.spi.impl;
import com.ricky.codelab.spi.DemoService;
public class DemoServiceImpl implements DemoService {
@Override
public String sayHi(String msg) {
return "Hello, "+msg;
}
}
那此时需要在META-INF/services中创建一个名为com.ricky.codelab.spi.DemoService的文件,其中的内容就为该实现类的全限定名:com.ricky.codelab.spi.impl.DemoServiceImpl。
如果该Service有多个服务实现,则每一行写一个服务实现(#后面的内容为注释),并且该文件只能够是以UTF-8编码。
tip 1
如果有多个实现,你取出的时候为集合,默认是文件实现类的顺序加载类,如果要自定义order方法,以便取出所有服务实现类后,可以按照设定进行排序
三、ServiceLoader的用途
之前我们只是配置好了SPI,但是SPI是如何真正在java程序中使用的,必须依靠ServiceLoader来动态加载Service的实现类了。
许多开发框架都使用了Java的SPI机制,如java.sql.Driver的SPI实现(mysql驱动、oracle驱动等)、common-logging的日志接口实现、dubbo的扩展实现等等。这些本质上,都是框架帮你用ServiceLoader做好了加载SPI等流程
META-INF/services/配置
在src/main/resources 下创建META-INF/services/目录,并新建com.ricky.codelab.spi.DemoService文件,内容如下:
#English implementation
com.ricky.codelab.spi.impl.EnglishDemoServiceImpl
#Chinese implementation
com.ricky.codelab.spi.impl.ChineseDemoServiceImpl
加载Service实现类
import java.util.Iterator;
import java.util.ServiceLoader;
import com.ricky.codelab.spi.DemoService;
ServiceLoader<DemoService> serviceLoader = ServiceLoader.load(DemoService.class);
Iterator<DemoService> it = serviceLoader.iterator();
while (it!=null && it.hasNext()) {
DemoService demoService = it.next();
System.out.println("class:"+demoService.getClass().getName()+"***"+demoService.sayHi("World"));
}
运行结果
···
class:com.ricky.codelab.spi.impl.DemoServiceImplHello, World
class:com.ricky.codelab.spi.impl.ChineseDemoServiceImpl你好, World
···
知识储备:
1.Meta-Inf文件夹
所谓META-INF, 说白了就是存放一些meta information相关的文件的这么一个文件夹, 一般来说尽量不要自己手工放置文件到这个文件夹。怎么理解这句话呢?就是说这个文件夹应该被看作是JAVA工程的一个内部META目录,所以这个目录下的文件应该都是build工具来生成的。我们自己的文件应该直接放到根目录下或者其他的子目录中。
根据官方的JAR file specification(http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html), 一个典型的META-INF目录下可能包含如下几种文件或者子目录:
MANIFEST.MF
INDEX.LIST
x.SF
x.DSA
services/
如果你将Jar中的META-INF文件夹删除,那么jar文件里边就没有MANIFEST.MF文件。那么,java -jar就找不到main class.
没有META-INF你仍然可以创建一个Jar文件。但是,当你想要执行jar文件的时候,这个jar是需要具备 META-INF/MANIFEST.MF的。