文章目录
- SPI
- dubbo SPI扩展点 与 java原生SPI扩展点:
- 示例展示
- JavaSPI
- Dubbo SPI
SPI
全称为 Service Provider Interface
,是一种服务发现机制。SPI
的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。正因此特性,我们可以很容易的通过 SPI
机制为我们的程序提供拓展功能。SPI
机制在第三方框架中也有所应用,比如Dubbo
就是通过 SPI
机制加载所有的组件。不过,Dubbo
并未使用 Java
原生的 SPI
机制,而是对其进行了增强,使其能够更好的满足需求。
在 Dubbo
中,SPI
是一个非常重要的模块。基于 SPI
,我们可以很容易的对 Dubbo
进行拓展。如果大家想要学习 Dubbo
的源码,SPI
机制务必弄懂。
dubbo SPI扩展点 与 java原生SPI扩展点:
Dubbo的扩展点的加载是从JDK标准的SPI扩展点发现机制加强而来的。
Dubbo改进了JDK标准的SPI的一下问题:
1. JDK
标准的SPI
会一次性实例化扩展点的所有实现,如果有的扩展实现初始化很耗时的话,而且这个耗时的加载还没用上的话,将会造成资源的浪费。
2. 如果扩展点加载失败,拿不到扩展点的名称。比如:JDK
标准的ScriptEngine
,通过 getName()
获取脚本类型的名称,但如果 RubyScriptEngine
因为所依赖的jruby.jar
不存在,导致 RubyScriptEngine
类加载失败,这个失败原因会被吃掉,和 ruby
对应不起来,当用户执行ruby
脚本时,会报不支持 ruby
的错,但这个异常不是真正失败的原因。
3. 增加了对扩展点的IOC
和AOP
的支持,一个扩展点可以直接setter
注入其他扩展点。
注意:源码版本均为 dubbo-2.6.4
示例展示
JavaSPI
前面简单介绍了
SPI
机制的原理,下面演示Java SPI
的使用方法。首先,我们定义一个接口,名称Robot
public interface Robot {
void sayHello();
}
接下来定义两个实现类,分别为
OptimusPrime
和Bumblebee
public class OptimusPrime implements Robot {
@Override
public void sayHello() {
System.out.println("Hello, I am OptimusPrime.");
}
}
public class Bumblebee implements Robot {
@Override
public void sayHello(){
System.out.println("Hello, I amBumblebee .");
}
}
接下来在
META-INF/services
文件下创建一个文件,名称为Robo
的全限定名org.appache.spi.Robot
,文件内容为实现类的全限定的类名,如下:
org.appche.spi.OptimusPrime
org.appche.spi.Bumblebee
做好所需要的准备工作,接下来编写测试代码
public class JavaSPITest {
ServiceLoader<Robot> serviceLoader = ServiceLoader.load(Robot.class);
System.out.println("Java SPI");
serviceLoader.forEach(Robot: :sayHello);
}
测试结果显示:
Dubbo SPI
Dubbo
并未使用Java SPI
,而是重新实现了一套功能更强的SPI
机制。Dubbo SPI
的相关逻辑被封装在了ExtensionLoader
类中,通过ExtensionLoader
我们可以加载指定的实现类。Dubbo SPI 所需的配置文件需放在META-INF/dubbo
路径下,配置内容如下:
optimusPrime = org.apache.spi.OptimusPrime
bumblebee = org.apache.spi.Bumblebee
与
Java SPI
实现类配置不同,Dubbo SPI
是通过键值对
的方式进行配置,这样我们可以按需加载指定的实现类。
另外,在测试Dubbo SPI
时,需要在Robot
接口上标注@SPI
注解。下面来演示Dubbo SPI
的用法:
public class DubboSPITest {
@Test
public void sayHello() throws Exception {
ExtensionLoader<Robot> extensionLoader = ExtensionLoader.getExtensionLoader(Robot.class);
Robot optimusPrime = extensionLoader.getExtension("optimusPrime");
optimusPrime.sayHello();
Robot bumblebee = extensionLoader.getExtension("bumblebee");
bumblebee.sayHello();
}
}
测试结果
Dubbo SPI 除了支持按需加载接口实现类,还增加了 IOC 和 AOP 等特性