java-SPI
什么是spi?
spi全称service provider interface,是java提供的一套用来被第三方实现和扩展的接口,是一种将服务接口与服务分离以达到解耦、大大提升了程序可扩展性的机制。引入服务提供者就是引入了spi接口的实现者,通过本地的注册发现获取到具体的实现类,轻松可插拔
使用
当访问的提供者提供了一种接口的实现之后,需要在classpath下的META-INF/services/
目录里创建一个以服务接口命名的文件,这个文件里的内容就是这个接口的具体的实现类。当其它的程序需要这个服务的时候,就可以通过查找这个jar包(一般都是以jar包做依赖)的META-INF/services/中的配置文件,配置文件中有接口的具体实现类名,可以根据这个类名进行加载实例化,就可以使用该服务了。jdk中查找服务的工具类是:java.util.ServiceLoader
应用场景
spi扩展机制应用场景有很多,比如Common-Logging、JDBC、Dubbo、Sharding-JDBC等
jdbc4.0以前,开发人员还需要基于Class.forName("xxx")的方式来装载驱动,jdbc4也基于spi的机制类发现驱动提供商了,可以通过META-INF/services/java.sql.Driver文件里指定实现类的方式来暴露驱动提供者
机制的约定
- 在META-INF/services/目录中创建以接口权限定命名的文件,该文件内容为api具体实现类的全限定名
- 使用ServiceLoader类动态加载META-INF中的实现类
- 如spi的实现类为jar则需要放在主程序ClassPath中
- api具体实现类必须有一个不带参数的构造方法
例子
-
创建接口
public interface SpiService { void getInfo(); }
-
创建实现类
public class SpiServiceImpl1 implements SpiService { @Override public void getInfo() { System.out.println("info...1"); } }
public class SpiServiceImpl2 implements SpiService { @Override public void getInfo() { System.out.println("info...2"); } }
-
在resources下创建META-INF/services/com.dqn.spi.service.SpiService文件
com.dqn.spi.service.impl.SpiServiceImpl1 com.dqn.spi.service.impl.SpiServiceImpl1
-
测试
ServiceLoader<SpiService> load = ServiceLoader.load(SpiService.class); for (SpiService spiService : load){ spiService.getInfo(); }