最近在看dubbo的源码,其中有了解到Java的SPI机制,特此记录下(更详细的介绍还请看官方文档)
同时也会记录下Dubbo SPI的实现方式
SPI初探
SPI的全称是Servcie Provider Interface,起初是提供给厂商做插件开发的
Java SPI使用了策略模式,一个接口多种实现。我们只声明接口,具体的实现并不在程序中直接确定,而是由程序之外的的配置掌控,用于具体实现的装配
和java spi 比较,dubbo SPI 做了一定的改进和优化,官方文档中描述如下:
- JDK标准的SPI会一次性实例化扩展点所有实现,如果有扩展实现则初始化很耗时,如果没有用上也加载,则浪费资源
- 如果扩展加载失败,则连扩展的名称都获取不到
- 增加了对扩展IOC和AOP的支持,一个扩展可以直接setter注入其他扩展。Dubbo SPI只加载配置文件中的类,并分成不同的种类缓存在内存中,而不会立即全部初始化
另外Dubbo SPI配置文件的用途,将其分成了三类目录:
- META-INF/services/ 目录:该目录下的 SPI 配置文件用来兼容 JDK SPI
- META-INF/dubbo/ 目录:该目录用于存放用户自定义 SPI 配置文件
- META-INF/dubbo/internal/ 目录:该目录用于存放 Dubbo 内部使用的 SPI 配置文件
然后,Dubbo 将 SPI 配置文件改成了 KV 格式,例如:
dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol
Java SPI实现步骤
- 定义一个接口以及对应的方法
- 编写该接口的一个实现类
- 在META-INF/services/目录下,创建一个以接口全路径命名的文件,文件内容为具体实现类的全路径名,如果有多个,用分行符号隔开
- 在代码中通过java.util.ServiceLoader来加载具体的实现类
java spi demo演示
- 定义1个service
public interface PrintService {
void sayHello();
}
- 定义实现类
public class PrintServiceImpl implements PrintService{
@Override
public void sayHello() {
System.out.println("hello java spi");
}
}
- resources中增加文件添加META-INF.service文件夹,并且在其中定义一个以接口全名为文件名称的文件,我的文件名称如下:
com.alibaba.dubbo.registry.spi.PrintService
- 文件内容是实现类的全路径,我的文件内容如下
com.alibaba.dubbo.registry.spi.PrintServiceImpl
- 测试方法:
public class TestSpi {
public static void main(String[] args) {
ServiceLoader<PrintService> services = ServiceLoader.load(PrintService.class);
for (PrintService printService : services) {
printService.sayHello();
}
}
}
不出意外,输出结果为:
hello java spi
dubbo spi demo
-
在resources目录下的META-INF中建立配置文件目录dubbo/internal
名称为:com.alibaba.dubbo.registry.spi.PrintService
内容为:impl=com.alibaba.dubbo.registry.spi.PrintServiceImpl -
在原来service上加上注解@SPI("impl")
@SPI("impl")
public interface PrintService {
void sayHello();
}
- 实现类保持不变
public class PrintServiceImpl implements PrintService{
@Override
public void sayHello() {
System.out.println("hello java spi");
}
}
- 测试方法:
public class TestDubboSpi {
public static void main(String[] args) {
PrintService printService = ExtensionLoader.getExtensionLoader(PrintService.class).getDefaultExtension();
printService.sayHello();
}
}
输出结果:
hello java spi
以上,感谢阅读,end!!!