dubbo SPI 主要配置技术解读
所谓SPI就是接口由框架定义,具体实现可以有不同供应商提供不同的实现。
dubbo在JDK基础上对SPI做了改进和扩展。
dubbo 的SPI 不但实现了实现类的动态加载,还实现了类似spring 的IOC,AOP的功能
本文就上述功能讲下具体使用方法
基本SPI 配置
dubbo 源码包的有些模块的 META-INF/dubbo/目录下 有以接口名命名的文件,里面有是 name=类全面形式的内容
比如
META-INF/dubbo/org.apache.dubbo.rpc.Protocol 文件的内容有
dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol
DubboProtocol的实现类是dubbo默认的调用协议实现
这样就可以在我们使用dubbo的配置文件中,通过 name 指定我们用的Protocol具体哪个实现
<dubbo:protocol name="dubbo"/>
同样你可以添加自己的实现类,比如x.y.z.XXXProtocol 让后在META-INF/dubbo/org.apache.dubbo.rpc.Protocol 文件中添加 新的一行 xxx=x.y.z.XXXProtocol 然后就可以在配置中使用了,这就是最基本的SPI功能。
IOC功能
dubbo不只是还实现了依赖注入的功能,比如DubboProtocol 先类种有个属性filter
public class DubboProtocol extends AbstractProtocol {
public Filter filter;
public void setFilter(Filter filter) {
this.filter = filter;
}
...
}
Filter 本身也一个接口,可以是@SPI接口,也可以是spring的一个bean
dubbo也可以自动从dubbo 扩展或者spring容器中找到实现类型自动注入
有个问题,如果dubbo org.apache.dubbo.rpc.Filter的文件中有多个实现配置,比如
mockfilter=org.apache.dubbo.config.mock.MockFilte
orc=org.apache.dubbo.config.orc.OrcFilte
mov=org.apache.dubbo.config.mov.MovFilter
应该用哪一个类呢?这就要用到Adaptive注解,比如
@Adaptive
public class MockFilter implements Filter {}
这个就表示用 MockFilter类作为实现类
关于@Adaptive注解,它还能写在接口方法上,如果不在类上指定dubbo 会为这个接口自动生成一个 接口名$Adpative 命名的实现类。比如 dubbo Protocol接口 refer方法
@SPI("dubbo")
public interface Protocol {
@Adaptive //没在类中指定,写在了方法上
<T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
.....
}
dubbo 动态生成的Adapatvie类和refer方法实现如下:
public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol {
.....
public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException {
if (arg1 == null) throw new IllegalArgumentException("url == null");
com.alibaba.dubbo.common.URL url = arg1;
String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
if (extName == null)
throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.refer(arg0, arg1);
}
......
}
可以看到,它实现的功能就是通过调用时url中的参数指定具体哪个实现类。
AOP
AOP就动态方法包装,完成切面编程,dubbo是通过 wrapper类实现的。
还是文件org.apache.dubbo.rpc.Protocol 文件,里面有这些配置
filter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrappe
listener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrappe
mock=org.apache.dubbo.rpc.support.MockProtocol
其中 ProtocolFilterWrapper就是Wrapper类,并不是因为类名有Wrapper,而是由于实现中有Protocol 接口类型的构造函数
@Activate(order = 100)
public class ProtocolFilterWrapper implements Protocol {
private final Protocol protocol;
public ProtocolFilterWrapper(Protocol protocol) {
if (protocol == null) {
throw new IllegalArgumentException("protocol == null");
}
this.protocol = protocol;
}
...
//对refer实现了包装
@Override
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
if (UrlUtils.isRegistry(url)) {
return protocol.refer(type, url);
}
return buildInvokerChain(protocol.refer(type, url), REFERENCE_FILTER_KEY, CommonConstants.CONSUMER);
}
}
//另外一个Wrappe
@Activate(order = 200)
public class ProtocolListenerWrapper implements Protocol {
private final Protocol protocol;
public ProtocolListenerWrapper(Protocol protocol) {
if (protocol == null) {
throw new IllegalArgumentException("protocol == null");
}
this.protocol = protocol;
}
...
}
想必你注意到了@Activate(order = 200)注解,它指定多个wrapper 的排序,通过@Activate的order属性排序。
Activate
比如常用的Filter, InvokerListener, ExportListener, TelnetHandler, StatusChecker 等实现集合,我们可以通过 Activate注解完成多个实现类的一次加载和激活,还能配置条件激活,比如
@Activate // 任何条件下激活
public class XxxFilter implements Filter {
// ...
}
@Activate(group = "provider", value = "cache") //这个就是在group是“provider” value 等于cache 下激活
public class CacheFilter implements Filter {
// ...
}
这个功能的实现可看 ExtensionLoader类的getActivateExtension方法:
- nyOJ-----韩信点兵
- HDUOJ-----A == B ?
- 用Oracle的眼光来学习MySQL 5.7的sys(上)(r11笔记第24天)
- Golang下通过syscall调用win32的api
- NYOJ----蛇形填数
- Golang语言 syscall 例子
- 用Oracle的眼光来学习MySQL 5.7的sys(下)(r11笔记第25天)
- HDUOJ-----Climbing Worm
- 闪回原理测试(二)(r11笔记第23天)
- SQL复习之为数据库用户赋予权限
- linux下syscall函数,SYS_gettid,SYS_tgkill
- 数据库收缩数据文件的尝试(三)(r11笔记第22天)
- 再议-Golang语言MessageBox用法实例
- linux下通过go语言获得系统进程cpu使用情况的方法
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- jQuery 选择器
- jQuery 介绍 以及基本使用
- 答应我,用了这个jupyter插件,别再重复造轮子了
- 商业数据分析从入门到入职(9)Python网络数据获取
- 谈一谈还原解包后小程序页面wxss样式的若干方法
- 什么?不使用selenium爬京东评论?你是不是在骗我
- 骚操作,Python操作PPT,你会吗?
- 用了这个jupyter插件,我已经半个月没打开过excel了
- Mística:一款支持任意协议的应用程序通信工具
- 为什么阿里巴巴禁止使用BigDecimal的equals方法做等值比较?
- 原创 | codefroces中的病毒,这题有很深的trick,你能解开吗?
- 原创 | git的远程分支是干啥的,和本地的有什么区别?
- 京东技术主导:全新架构的分布式事务Hmily 2.1.1发布
- iOS音视频接入-TRTC接入前期key、秘钥等准备
- 你一定不知道的 Linux 使用技巧