Dubbo SPI
为什么要了解Dubbo SPI , Dubbo 框架所有的功能都可以扩展,Dubbo 扩展的SPI,能够根据请求参数 自适应选择匹配的SPI 实现,并且Dubbo 自动包装机制很容易实现 AOP 功能。 Dubbo 源码中大量使用了这些特性,掌握Dubbo SPI 对理解Dubbo 框架至关重要。 本文主要内容
Dubbo SPI 使用Demo
Dubbo 自适应扩展点Demo
Dubbo 自动包装扩展点Demo
Dubbo SPI
Dubbo 的扩展点加载从 JDK 标准的 SPI (Service Provider Interface) 扩展点发现机制加强而来
Dubbo SPI 兼容 JDK SPI 并且做了改进,Dubbo 改进了 JDK 标准的 SPI 的以下问题:
- JDK 标准的 SPI 会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源。
- 如果扩展点加载失败,连扩展点的名称都拿不到了。比如:JDK 标准的 ScriptEngine,通过 getName() 获取脚本类型的名称,但如果 RubyScriptEngine 因为所依赖的 jruby.jar 不存在,导致 RubyScriptEngine 类加载失败,这个失败原因被吃掉了,和 ruby 对应不起来,当用户执行 ruby 脚本时,会报不支持 ruby,而不是真正失败的原因。
- 增加了对扩展点 IoC 和 AOP 的支持,一个扩展点可以直接 setter 注入其它扩展点。
Dubbo SPI 使用
- 定义 SPI 接口,并添加SPI注解。 @SPI("json") 默认实现是json 实现
@SPI("json")
public interface CodeC {
void serialize();
}
2. 实现类
``` java
public class JSONCodeC implements CodeC{
@Override
public void serialize() {
System.out.println("JSONCodeC");
}
}
public class XMLCodeC implements CodeC{
@Override
public void serialize() {
System.out.println("XMLCodeC");
}
}
- dubbo spi 配置
META-INF.dubbo 新增文件,文件名为SPI 接口全路径如com.codetonight.spi.CodeC
文件内容
json=com.codetonight.spi.wrap.JSONCodeC
xml=com.codetonight.spi.wrap.XMLCodeC
- Dubbo SPI 加载
extensionLoader.getExtension 获取对应的SPI 实现。
ExtensionLoader<CodeC> extensionLoader = ExtensionLoader.getExtensionLoader(CodeC.class);
CodeC codeC = extensionLoader.getExtension("xml");
codeC.serialize();
扩展点自适应
所有扩展点参数都包含 URL 参数中,URL 作为上下文信息贯穿整个扩展点设计体系。
扩展点自适应就是Dubbo框架能够自动获取URL 中参数,然后匹配对应的SPI 实现。
扩展点自适应,需要至少一个参数是URL 类型 或者 参数的一个get方法返回URL 类型。
前面接口稍加修改让其支持自适应, Dubbo 扩展点自适应,直到扩展点方法执行时才决定调用是哪一个扩展点实现。
@Adaptive("type") URL中参数type 控制对应SPI自适应实现。
@SPI("json")
public interface CodeC {
@Adaptive("type")
void serialize(URL url);
}
ExtensionLoader<CodeC> extensionLoader = ExtensionLoader.getExtensionLoader(CodeC.class);
CodeC codeC = extensionLoader.getAdaptiveExtension();
// URL 未指定type,取默认SPI 实现
codeC.serialize(URL.valueOf("http://localhost:9999/xxx"));
// URL type=xml ,name = xml对应的SPI XMLCodeC 实现
codeC.serialize(URL.valueOf("http://localhost:9999/xxx?type=xml"));
扩展点自动包装
自动包装类满足如下特征包含对应SPI接口类型的构造方法,如下面例子CodeCWrap ,具有构造方法public CodeCWrap(CodeC codeC)
还需要在com.codetonight.spi.CodeC文件中加上该SPI 实现codecwrap=com.codetonight.spi.wrap.CodeCWrap
这样就自动实现了AOP 功能,我们也可以添加多个包装类。
public class CodeCWrap implements CodeC{
private CodeC codeC;
public CodeCWrap(CodeC codeC) {
this.codeC = codeC;
}
@Override
public void serialize(URL url) {
System.out.println(" before wrap ...");
codeC.serialize(url);
System.out.println(" end wrap ...");
}
}
总结
Dubbo SPI 整个源码几乎随处可见,掌握Dubbo SPI 能够轻松定制化各种扩展配置,并且对源码学习理解帮助很多,否则你会一头雾水,这里的SPI实现实现选择的是哪个实现。