Dubbo 源码分析 - Dubbo SPI 在 Protocol 层 的应用

原创
03/28 18:06
阅读数 304

开篇

前面通过三篇文章讲述了 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 在这里插入图片描述 从上面的时序图中可以看出:
  1. 在 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, 最终才会调用目标实例 RegisterProtocol 或者 DubboProtocol

在这里插入图片描述

在这里插入图片描述

总结

Dubbo 优秀的原因之一在于它的扩展性非常强, 而这种特性是基于 SPI 扩展接口实现的.

Dubbo SPI 是对 JDK SPI 的一种增强实现, 其中包括:

  • 通过 @Adaptive注解实现扩展点自适应
  • 对扩展接口的 IOC(使用 set 方法注入其他扩展接口)
  • 对 AOP 的支持 (使用 Wrapper 类对扩展接口的功能进行增强)
  • 其他

本文对 Dubbo 的 Protocol 层的扩展讨论, 就有涉及到上述的使用方法, 因此才出现了在 ServiceConfig 中调用 Protocol#export方法, 会经过多个 Protocol 的实现.

同时也说明了一点, 要想搞懂 Dubbo 的源码, 必须对其扩展机制有一定的认知.

展开阅读全文
打赏
0
0 收藏
分享
加载中
你好,看了你的文章,觉得你是一名对技术很有追求的同学,请问有兴趣加入菜鸟国际物流技术部吗?
03/28 22:24
回复
举报
更多评论
打赏
1 评论
0 收藏
0
分享
返回顶部
顶部