Dubbo SPI 概述

Dubbo 通过 SPI 机制提供了非常灵活的可扩展性

扩展设计思路

可扩展性是任何系统都在追求的,对于 Dubbo 同样适用。

什么是可扩展性

可扩展性是一种设计理念,代表着我们对未来的展望,我们希望基于现有的架构或者设计,在未来发生某些方面的变化的时候,我们可以以最小的代价来适应这种变化。

可扩展性的优点

可扩展性的优点主要体现在模块之间解耦,符合开闭原则,对扩展开放,对修改关闭。当系统需要新增功能的时候,无需修改现有系统的结构和代码,只需要新增一个扩展即可。

扩展的实现

一般来说,系统会采用 Factory、IoC、OSGI 等方式来管理扩展(插件)的生命周期。考虑到 Dubbo 的适用性,不想强依赖 Spring 等 IoC 容器。而自己构建一个小的 IoC 容器,又觉得有点过度设计,因此选择最简单的 Factory 方式来管理扩展(插件)。在 Dubbo 中,所有内部实现和第三方实现都是平等对待的。

Dubbo 中的可扩展性

  • 平等对待第三方实现。在 Dubbo 中,所有内部实现和第三方实现都是平等对待的,用户可以根据自己的业务需要,替换掉 Dubbo 提供的原生实现。
  • 每个扩展点只封装一个变化因素,最大化复用。每个扩展点的实现者,往往只关心一件事情。用户如果需要扩展,只需要扩展自己关心的扩展点即可,大大减少了用户的负担。

Dubbo 扩展的特点

Dubbo 中的扩展能力,是在 JDK 标准的 SPI 扩展点发现机制上增强而来,改进 JDK 标准 SPI 的以下问题

  • JDK 标准的 SPI 会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源。
  • 如果扩展点加载失败,连扩展点的名称都拿不到了。例如:JDK 标准的 ScriptEngine,通过 getName() 获取脚本类型名称,但如果 ruby 脚本引擎实现为 RubyScriptEngine,假设当前 JVM 里没有 jruby.jar,导致 RubyScriptEngine 类加载失败,这个失败原因被吃掉了,和 ruby 对应不起来,当用户执行 ruby 脚本时,会报不支持 ruby,而不是真正失败的原因。

基于 Dubbo 提供的扩展能力,用户可以很方便的根据自己的需要扩展其他的协议、过滤器、路由等。下面介绍 Dubbo 扩展能力的特点。

  • 按需加载。Dubbo 的扩展能力不会一次性实例化所有实现类,而是配合扩展类一起实例化,减少资源浪费。
  • 增加了扩展类的 IOC 能力。Dubbo 的扩展能力并不仅仅是发现扩展服务实现类,而是在此基础上更进一步,如果扩展类的属性依赖其他的对象,Dubbo 会自动完成依赖对象的注入功能。
  • 增加了扩展类的 AOP 能力。Dubbo 的扩展能力会自动发现扩展类的 Wrapper 类,完成 Wrapper 类的构建,增强扩展类的功能。
  • 具备动态选择扩展实现的能力。Dubbo 扩展会根据参数,在运行时动态的选择相应的扩展类,提升了 Dubbo 的灵活性。
  • 扩展实现可以排序。可以根据用户的需求,指定扩展实现的执行顺序。
  • 提供了扩展点的自适应能力。该能力可以让部分扩展类在消费者端生效,部分扩展类在提供者端生效。

从 Dubbo 扩展的设计目标可以看出,Dubbo 实现的一些特性,比如扩展实现的动态选择、IOC、AOP 等,可以为用户提供非常灵活的扩展能力。

Dubbo 扩展加载流程

Dubbo 加载扩展的整个流程如下

//imgs/v3/concepts/extension-load.png

主要有 4 个步骤

  • 读取并解析配置文件
  • 缓存所有扩展实现
  • 根据用户执行的扩展名,实例化相应的扩展实现
  • 执行扩展实例属性的 IOC 注入,并实例化扩展 Wrapper 类,实现 AOP 特性

如何使用 Dubbo 的扩展能力进行扩展

下面以扩展协议为例,说明如何使用 Dubbo 提供的扩展能力扩展 Triple 协议。

(1)在协议实现 jar 包中放置一个文本文件:META-INF/dubbo/org.apache.dubbo.remoting.api.WireProtocol

tri=org.apache.dubbo.rpc.protocol.tri.TripleHttp2Protocol

(2)实现类内容

@Activate
public class TripleHttp2Protocol extends Http2WireProtocol {
    //...
}

说明:Http2WireProtocol 实现了 WireProtocol 接口

(3)在 Dubbo 配置模块中,每个扩展点都有对应的配置属性或标签,配置中指定使用哪个扩展。例如

<dubbo:protocol name="tri" />

从上面的扩展步骤可以看出,用户基本是在黑盒下完成扩展的。

Dubbo 扩展应用

Dubbo 的扩展能力非常灵活,在其自身功能的实现中无处不在。

//imgs/v3/concepts/extension-use.png

Dubbo 的可扩展性使得 Dubbo 项目可以很方便地将各个子模块逐一拆分出来,实现热插拔的功能。用户可以根据自己的需要,完全替换 Dubbo 的原生实现,以满足自身的业务需求。

使用场景

  • 如果需要自定义负载均衡策略,可以使用 Dubbo 的扩展性。
  • 如果需要实现自定义注册中心,可以使用 Dubbo 的扩展能力。
  • 如果需要实现自定义过滤器,可以使用 Dubbo 的扩展能力。

Dubbo 扩展对内部实现和第三方实现一视同仁。更多使用场景,请参考 SPI 扩展实现


上次修改时间:2023 年 1 月 2 日: 增强英文文档 (#1798) (95a9f4f6c1c)