Soul网关源码阅读(十六)—— SPI插件

SPI 概念

SPI(Service Provider Interface),是一种模块间相互引用的机制,可以用来启用框架和替换组件,一般的流程是服务的提供者在classpath指定配置实现类的全名,由调用方读取和加载使用,调用方无需修改代码,通常以jar包的形式引入需要使用的实现,Dubbo,Soul等项目使用了SPI机制,但给使用者提供了更丰富便捷的选择,可以由用户安优先级,名称等方式选择使用那个实现。
SPI 标准流程:

  • 定义标准接口
  • 编写不同的实现,配置classpath目录指定位置
  • 使用方加载使用

Soul网关源码阅读(十六)—— SPI插件_第1张图片

JDK内置的SPI

JDK内置的SPI 机制 ,约定好的classpath目录下META_INFO/services/ 创建一个以服务接口命名的文件,该文件中内容为该接口的实现类(完全名称即包含package名称)通过java.util.ServiceLoader加载指定接口
举个栗子

  1. 我们定义一个LearnSpi interface
    package com.cuicui.bootcamp
    public interface LearnSpi {
    void readBook();
    }

  2. 我们一个school的学习工程打包为school.jar 里面实现类:
    package com.cuicui.bootcamp
    import com.cuicui.bootcamp.LearnSpi
    public class SchoolLearnSpi implements LearnSpi {
    public void readBook(){
    System.out.println(“School readBook”);
    }
    }

需要在school工程的classpath目录下META_INFO/services/ 中新建一个名为
com.cuicui.bootcamp. LearnSpi的文件
文件的内容为
com.cuicui.bootcamp.SchoolLearnSpi

  1. 调用者可以引入school.jar 并通过java.util.ServiceLoader加载获取
    ServiceLoader serviceLoader = ServiceLoader.load(LearnSpi.class);
    for (LearnSpi LearnSpi : serviceLoader) {
    LearnSpi.readBook();
    }
    // 在终端就会打印 : School readBook

JDK默认的SPI机制在使用的时候我们没有办法获取到我们想要的特定的实现,只能通过for循环一个一个遍历匹配,也没有命名,实际很难使用。

Soul中的spi

Soul 的spi机制,是由Soul-spi这个项目负责实现,并借鉴Dubbo SPI的实现
ExtensionLoader 提供了比JDK ServiceLoader更为强大的功能。

ExtensionLoader

我们这里重点分析ExtensionLoader
类成员有:
// soul spi的扩展目录

private static final String SOUL_DIRECTORY = "META-INF/soul/";

// 不同扩展接口对应的ExtensionLoader的缓存类,静态成员

private static final Map<Class<?>, ExtensionLoader<?>> LOADERS = new ConcurrentHashMap<>();

// 扩展接口类

private final Class clazz;

// 自定的Holder 类型,cachedClasses 用于存储不同扩展对应的实现类们

private

你可能感兴趣的:(后端,soul)