apache shenyu的spi机制
Contents
什么是spi
SPI
就是Service Provider Interface
,是一种动态的服务发现机制。
可以基于运行时动态的加载接口的实现类。通过(接口编程 + 策略模式 + 配置文件) 实现解耦
和扩展
。
应用
- 数据库驱动
- 基于该接口的实现有
MySQL
,PostgreSQL
,SqlServer
等。
- 基于该接口的实现有
- SLF4J日志框架
Dubbo
的SPI
扩展- dubbo
- apache shenyu
spring boot starter
jdbc的应用
日志的应用
apache shenyu的spi应用
dubbo的spi应用
实现方式
市面上常见的SPI的实现方式有:
JDK
的SPI
实现Dubbo
的SPI
实现、ShenYu
的SPI
Spring
的SPI
实现
JDK
的SPI
实现流程为
- 在类路径的
META-INF/services
目录创建一个以接口全限定名称命名的文件(本质是一个properties)文件,例如命名为java.sql.Driver - 该文件中可以指定具体的实现类,也就是每个实现类的全类型限定名为单独一行
- 例如
META-INF/services/java.sql.Driver
-
# META-INF/services/java.sql.Driver文件内容 com.mysql.jdbc.Driver org.postgresql.Driver
- 例如
- 最后通过
java.util.ServiceLoader
对该文件进行加载,实例化接口的对应实现类(这里隐含了一个约定,所有实现类必须提供无参构造函数,用来反射调用)
底层的实现涉及到类加载、双亲委派等内容,这里不展开。基于这种设计思路,很多主流框架实现了一套SPI
扩展,例如Dubbo
的SPI
扩展模块,就是读取类路径
下META-INF/services/dubbo
目录的文件内容进行类加载。ShenYu-SPI
模块也是沿用类似的设计思路。
JDK SPI 的代码示例
- 接口定义
public interface Search {
public List<String> searchDoc(String keyword);
}
- 实现类
public class FileSearch implements Search{
@Override
public List<String> searchDoc(String keyword) {
System.out.println("文件搜索 "+keyword);
return null;
}
}
public class DatabaseSearch implements Search{
@Override
public List<String> searchDoc(String keyword) {
System.out.println("数据搜索 "+keyword);
return null;
}
}
- resources 接下来可以在resources下新建META-INF/services/目录,然后新建接口全限定名的文件:
com.xxx.Search
,里面加上我们需要用到的实现类
com.xxx.FileSearch
- 测试方法
public class TestCase {
public static void main(String[] args) {
ServiceLoader<Search> s = ServiceLoader.load(Search.class);
Iterator<Search> iterator = s.iterator();
while (iterator.hasNext()) {
Search search = iterator.next();
search.searchDoc("hello world");
}
}
}
- 总结
可以看到输出结果:文件搜索 hello world如果在com.xxx.Search文件里写上两个实现类,那最后的输出结果就是两行了。
这就是因为ServiceLoader.load(Search.class)
在加载某接口时,会去META-INF/services
下找接口的全限定名文件,
再根据里面的内容加载相应的实现类。这就是spi的思想,接口的实现由provider实现,provider只用在提交的jar包里的META-INF/services
下根据平台定义的接口新建文件,并添加进相应的实现类内容就好。
ShenYu SPI
源码分析
ShenYu-SPI
模块十分精炼,代码结构如下
- shenyu-spi[module]
- org.apache.shenyu.spi[package]
-- ExtensionFactory
-- ExtensionLoader
-- Join
-- SPI
-- SpiExtensionFactory
这些类的功能如下
ExtensionFactory
:SPI
加载工厂,本身也是一个SPI
,用于基于SPI
机制加载ExtensionLoader
实例同时基于ExtensionLoader
实例获取默认标记SPI
标识接口的实现SpiExtensionFactory
:ExtensionFactory
的一个实现类SPI
: 标识注解,用于标识SPI
,用于接口上Join
: 标识注解,用于实现类上,用来给SPI
的实现进行排序。ExtensionLoader
:SPI
加载器,类比java.util.ServiceLoader
,用于加载SPI中接口的实现类