dubbo
开篇
前面通过三篇文章讲述了 Dubbo SPI 的其中三种用法:
本文通过 Dubbo 的一个应用案例 - 获取 Protocol 扩展实例, 来看看 Dubbo SPI 在源码中的具体应用实现.
阅读本文之前,请结合上述文章 或者 官网 Dubbo SPI, 或者其他相关文章, 对 Dubbo SPI 有一定程度的了解.
正文
通过 Dubbo 官方文档-框架设计篇, 可以看出 Dubbo 整体被分为 十 层, 其中 Service 和 Config 层为 API,其它各层均为 SPI, 也就是说其他各层都有对应的多个扩展实现.
比如协议层 Protocol 的已知扩展:
- org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol
- org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol
- org.apache.dubbo.rpc.protocol.rmi.RmiProtocol
- org.apache.dubbo.rpc.protocol.http.HttpProtocol
- org.apache.dubbo.rpc.protocol.http.hessian.HessianProtocol
本文就 Protocol 扩展点来看下 Dubbo 是如何应用的.
Protocol 扩展点
如下所示, 为 Protocol 的部分源码,
@SPI("dubbo")
public interface Protocol {
// 省略其他代码
@Adaptive
<T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
}
根据我们之前讲的 Dubbo SPI 的使用方法, 我们可以得出以下几个结论:
- SPI 注解 value 值为 dubbo, 也就是 Protocol 层默认使用的是 Dubbo 协议
- export 方法上的
@Adaptive
注解表明该方法作为一个自适应扩展点, 也就是会动态生成一个 Protocol$Adaptive 实例
部分代码如下所示, 完整版请到 Dubbo SPI 使用方法(二)- 扩展点自适应 文章末尾
public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol {
public org.apache.dubbo.rpc.Exporter export(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException {
// 省略部分代码
}
}
接下来, 通过 Dubbo 的服务暴露流程看下 Protocol 扩展的具体应用.
服务暴露流程
因为 Dubbo(2.7.x) 本身支持很多协议,以及暴露方式, 而以下的内容基于: 将一个服务注册到 zookeeper 中, 进行远程暴露(dubbo 协议),
远程服务暴露流程(粗略版)
这是服务暴露的一个大概的时序图, 详细的后面会继续讨论,
- 先经过 RegisterProtocol
-
再经过 DubboProtocol
在这里插入图片描述
从上面的时序图中可以看出:
- 在 ServiceConfig 的
doExportUrlsFor1Protocol
方法中调用 Protocol 的export
方法
private void doExportUrlsFor1Protocol() {
// 省略一堆流程
Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);
}
而我们的 PROTOCOL 定义如下:
private static final Protocol PROTOCOL = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
因此我们可以得知, 这里获取的是一个自适应扩展实例, 因为 URL 参数中携带协议是 registry,所以先获得的是上面时序图中提到的 RegisterProtocol, 处理完后,才是 DubboProtocol.
除此之外, 根据我们之前讲过的 Dubbo SPI 的另一种使用方法: 扩展点自动包装 , 我们可以看到 Protocol 定义了如下 Wrapper:
qos=org.apache.dubbo.qos.protocol.QosProtocolWrapper
filter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper
远程服务暴露流程(略详细版)
结合上面的内容, 我们对上面的时序图做一个较详细的补充:
每次通过 Protocol 获取扩展实例时, 都会依次经过 Protocol$Adaptive, QosProtocolWrapper, ProtocolListenerWrapper, ProtocolFilterWrapper
, 最终才会调用目标实例 RegisterProtoco
l 或者 DubboProtocol
总结
Dubbo 优秀的原因之一在于它的扩展性非常强, 而这种特性是基于 SPI 扩展接口实现的.
Dubbo SPI 是对 JDK SPI 的一种增强实现, 其中包括:
- 通过
@Adaptive
注解实现扩展点自适应 - 对扩展接口的 IOC(使用 set 方法注入其他扩展接口)
- 对 AOP 的支持 (使用 Wrapper 类对扩展接口的功能进行增强)
- 其他
本文对 Dubbo 的 Protocol 层的扩展讨论, 就有涉及到上述的使用方法, 因此才出现了在 ServiceConfig 中调用 Protocol#export
方法, 会经过多个 Protocol 的实现.
同时也说明了一点, 要想搞懂 Dubbo 的源码, 必须对其扩展机制有一定的认知.
网友评论