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);
    }

结果: 

 

 

 

 

posted @   布里。  阅读(119)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示