一、Java SPI vs Dubbo SPI

  1. JDK 标准的 SPI 会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加 载,会很浪费资源

  2. 如果有扩展点加载失败,则所有扩展点无法使用

  3. 提供了对扩展点包装的功能(Adaptive),并且还支持通过set的方式对其他的扩展点进行注入

二、介绍

1 dubbo中大量的使用了SPI来作为扩展点,通过实现同一接口的前提下,可以进行定制自己的实现类。 比如比较常见的协议,负载均衡,都可以通过SPI的方式进行定制化,自己扩展。Dubbo中已经存在的 所有已经实现好的扩展点。

2 Dubbo中默认提供的负载均衡策略。
image.png

三、Demo 基于第一节实现

1 项目搭建

image.png

2 api 模块依赖引入

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.apache.dubbo</groupId>
  4. <artifactId>dubbo</artifactId>
  5. <version>3.0.2.1</version>
  6. </dependency>
  7. </dependencies>

3 指定默认实现 和 扩展注解

Dubbo中的Adaptive功能,主要解决的问题是如何动态的选择具体的扩展点。通过 getAdaptiveExtension 统一对指定接口对应的所有扩展点进行封装,通过URL的方式对扩展点来进行 动态选择。 (dubbo中所有的注册信息都是通过URL的形式进行处理的。)
image.png

4 扩展实现

image.png
image.png
image.png

5 SPI 配置

image.png

6 测试类

1 自定义的URL

  1. public class DubboAdaptiveMain {
  2. public static void main(String[] args) {
  3. URL url = URL.valueOf("test://localhost/hello?hello.service=animal");
  4. final HelloService adaptiveExtension = ExtensionLoader.getExtensionLoader(HelloService.class).getAdaptiveExtension();
  5. String sayHello = adaptiveExtension.sayHello(url);
  6. System.out.println(sayHello);
  7. }
  8. }

image.png
2 使用默认指定的Service

  1. public class DubboAdaptiveMain {
  2. public static void main(String[] args) {
  3. URL url = URL.valueOf("test://localhost/hello");
  4. final HelloService adaptiveExtension = ExtensionLoader.getExtensionLoader(HelloService.class).getAdaptiveExtension();
  5. String sayHello = adaptiveExtension.sayHello(url);
  6. System.out.println(sayHello);
  7. }
  8. }

image.png

注意:
1 因为在这里只是临时测试,所以为了保证URL规范,前面的信息均为测试值即可。

2 关键的点在于 hello.service 参数,这个参数的值指定的就是具体的实现方式。

3 hello.service 是因为这个接口的名称,其中后面的大写部分被dubbo自动转码为 . 分割。

4 通过 getAdaptiveExtension 来提供一个统一的类来对所有的扩展点提供支持(底层对所有的扩展 点进行封装)。

5 调用时通过参数中增加 URL 对象来实现动态的扩展点使用。

6 如果URL没有提供该参数,则该方法会使用默认在 SPI 注解中声明的实现。