SPI机制浅析
SPI 全程是 Servcie Provider Interface :它是一种代码的思想 , 主要的功用是用于解耦代码 ,也是一种"服务的发现机制" 。一定程度上遵循了开闭原则。Java生态就很多组件就是使用了这样的思想实现了组件化的功能 或者 可扩展性。

举个现实的例子:
比如你是一个商户需要去商城租一个铺位 那么你就需要去商场的平台办理一些固定的手续 ,那么商场的平台就会知道你在哪里 后续有客人到你的铺位消费 ,平台就知道了,这个时候来了第二个人需要租另一个铺位,则也需要去商场的平台去办理固定手续 ,如果你想租这样的一个铺位,则必须去商城的平台办理手续,如果没有去办理手续的话 是不合法的也是不被商场承认的。
以上就是SPI的现实的一个例子 商城的平台注册的固定手续可以理解为 SPI ,客户一 和客户二 则遵循了SPI的规范才可以在商场的铺位上营业。客户三没有遵循则是不合法的
再用一个Java的生态组件来说说这个SPI机制
SpringBoot是有一个自动装配的功能比如说什么什么AutoConfiguration....都是利用SpringBoot对SPI思想的实现完成的,不信你们可以看看SpringBoot的autoconfig源码 在Resorces下的META-INF下spring.factories
大概流程是这样的 SpringBoot实现了auto装配的机制(SPI思想的一种实现),他让一些想扩展或者想实现自动化配置的组件把包路径写在spring.factories 下,让SpringBoot在启动的时候可以发现这一些自动配置的组件 可以参考SpringFactoriesLoader这个类
下面就看我的简单实现把 : 定义了一个接口,让不同的程序实现这个接口 ,最后通过把这些实现接口的类的包路径放在Resources下的META-INF的animal下的conf.txt文件下 。 这样的话不论是谁实现我这个接口只需要在他的Jar包下的同样为定义好即可被我的程序调用
//接口类 public interface Animal { /** * 动物叫声 */ void say(); }
//实现类 public class Cat implements Animal { @Override public void say() { System.out.println("我是猫------喵喵喵!!!"); } }
//处理类 public class AnimalLoader { private static final String LOAD_PATH = "META-INF/animal/conf.txt"; private List<Animal> list = new ArrayList<>(); public List<Animal> loadCustomAnimal() throws IOException { final Enumeration<URL> resources = App.class.getClassLoader().getResources(LOAD_PATH); BufferedReader reader = null; while (resources.hasMoreElements()) { final URL url = resources.nextElement(); reader = new BufferedReader(new FileReader(url.getPath())); final Stream<String> lines = reader.lines(); if(lines != null) { lines.forEach(this::processor); } } return list; } private void processor(String className) { try { final Class<?> aClass = Class.forName(className); if (Animal.class.isAssignableFrom(aClass)) { final Animal animal = (Animal) aClass.newInstance(); list.add(animal); } }catch (Exception e) { e.printStackTrace(); } } }
再看看conf.txt的位置

内容

调用接口的地方
public static void main(String[] args) throws IOException { //加载自定义的类 AnimalLoader animalLoader = new AnimalLoader(); final List<Animal> animals = animalLoader.loadCustomAnimal(); //使用加载的类 animals.forEach(Animal::say); }
结果: 

浙公网安备 33010602011771号