跳转至

Dubbo SPI 原理

一、什么是 SPI

SPI(Service Provider Interface)是一种动态加载扩展点的机制。Java 自带 ServiceLoader,Dubbo 在此基础上做了增强。

二、Java 原生 SPI 的问题

ServiceLoader<Driver> loader = ServiceLoader.load(Driver.class);
  • 会一次性实例化所有实现,不支持按需加载。
  • 实现之间没有依赖注入 / 包装。
  • 失败时难以定位是哪个实现出问题。

三、Dubbo SPI 做了什么

Dubbo 在 META-INF/dubbo/ 目录下配置扩展点:

META-INF/dubbo/org.apache.dubbo.remoting.Transporter

内容:

netty=org.apache.dubbo.remoting.transport.netty.NettyTransporter
mina=org.apache.dubbo.remoting.transport.mina.MinaTransporter

用法:

ExtensionLoader<Transporter> loader =
    ExtensionLoader.getExtensionLoader(Transporter.class);
Transporter netty = loader.getExtension("netty");

四、核心能力

1. 按需加载

按 key 加载具体实现,不一次性实例化所有。

2. IOC(依赖注入)

Dubbo SPI 支持 setter 注入:如果扩展实现依赖另一个扩展,Dubbo 会自动注入。

3. AOP(包装类)

Wrapper 类:

public class TransporterWrapper implements Transporter {
    private final Transporter transporter;
    public TransporterWrapper(Transporter t) { this.transporter = t; }
}

Dubbo 自动识别 Wrapper,在加载真实实现时包装一层。

4. Adaptive(自适应扩展)

@Adaptive 注解让方法调用时根据 URL 参数动态选择实现:

@SPI("dubbo")
public interface Protocol {
    @Adaptive
    int getPort(URL url);
}

调用时 Dubbo 生成一个 Protocol$Adaptive,根据 url.getProtocol() 选择具体实现。

5. Activation(激活)

@Activate 按条件自动激活扩展,如过滤器。

五、Dubbo 启动时做了什么

  1. 扫描所有 META-INF/dubbo/ 下的配置文件。
  2. 把每个扩展点的 key → 实现类缓存到内存。
  3. 根据 URL 参数选择具体实现。
  4. 注入依赖、包装 AOP、生成 Adaptive。

高频追问

  • Dubbo SPI vs Java SPI:按需加载、IOC、AOP、自适应。
  • @SPI("dubbo"):默认实现是 dubbo。
  • Dubbo 几乎所有核心组件(Protocol、Transport、Serialiation、Cluster、LoadBalance)都是 SPI 扩展。