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); }
结果:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix