总结:就是javase约定好规范,然后就能通过serviceLoader,来找到具体的实现类。
这样,上层可以直接接口调用,然后下层应用比如依赖jar包,去不同的实现这个接口,然后把这个接口实现类放到META-INF/services/路径就好了,来达到各自的需求。简单的例子,比如不同数据库的jdbc驱动包。
SPI其实就是一种约定好规范,规定好在classpath下的META-INF/services/路径下,放置指定接口的指定实现类,然后java提供了ServiceLoader类,这个类会去读取这个文件,然后通过文件中指定的接口实现类,然后class.forName()加载这个类。
比如jdbc的驱动包,java.sql.Driver只是一个接口,oracle 的驱动包ojdbc.jar在META-INF/services下就有文件以java SPI的规范指定了这个接口的实现类。
所以在这种规范下,有很好的扩展性。只要依赖不同的jar包,就有不同的实现。
这里有个网上的例子:
public interface IShout {
void shout();
}
public class Dog implements IShout {
@Override
public void shout() {
System.out.println("wang wang");
}
}
public class Cat implements IShout {
@Override
public void shout() {
System.out.println("miao miao");
}
}
META-INF/services/org.foo.demo.IShout文件内容
org.foo.demo.Dog
org.foo.demo.Cat
测试
public class SPIMain {
public static void main(String[] args) {
ServiceLoader<IShout> shouts = ServiceLoader.load(IShout.class);
for (IShout s : shouts) {
s.shout();
}
}
}
既然是一个约定好的规范,那么,自然,你也可以约定好一个规范,然后自己做一个类似serviceLoader的加载器,然后去加载实现类就可以了,只要,让别人遵守这个规范就好了,比如,dubbo。