Java spi和Dubbo spi的对比以及应用

Spi测试的基础环境
一个Shape的接口,有一个draw方法
一个Circle类和Rect类实现Shape,重写draw方法

代码如下:

// 接口:形状
public interface Shape {
    void draw();
}

// 圆类,实现形状接口
public class Circle implements Shape {
    public void draw() {
        System.out.println("画一个圆");
    }
}

// 矩形类,实现形状接口
public class Rect implements Shape {
    public void draw() {
        System.out.println("画一个矩形");
    }
}
Java的Spi
  1. 在resources下创建一个META-INF/services/文件夹
  2. 创建以Shape接口的全限定名为文件名
  3. 在文件里写需要加载的子类

在这里插入图片描述
在这里插入图片描述

  1. 编写测试类,通过ServiceLoader类来获取Shape下的在配置文件里配置的子类。
public class JavaSpiTest {

    public static void main(String[] args) {
        Shape shape;
        ServiceLoader<Shape> serviceLoader = ServiceLoader.load(Shape.class);
        Iterator<Shape> iterator = serviceLoader.iterator();
        while (iterator.hasNext()) {
            shape = iterator.next();
            shape.draw();
        }
    }
}
  1. 结果
    在这里插入图片描述
  2. 总结,JavaSpi的机制会加载配置文件里所有的类,但是如果你只需要几个类,会造成空间的浪费。
Dubbo的Spi
dubbo的spi对java spi的弊端做了改进。
相比于java spi的全量加载,dubbo spi 可以做到按需加载。
  1. 在resources下创建一个META-INF/dubbo/文件夹(注意:dubbo可以加载三个文件夹,这里以dubbo文件夹测试)
    在这里插入图片描述
  2. 在dubbo文件夹下创建以接口全类名为名的文件,在里面创建以key = val的形式编写。

在这里插入图片描述
在这里插入图片描述

  1. 在接口上加@Spi的注解,@SPI("circle")表示指定默认的加载项
@SPI("circle")
public interface Shape {
    void draw();
}
  1. 测试类
public class DubboSpiTest {
    public static void main(String[] args) {
        ExtensionLoader<Shape> extensionLoader = ExtensionLoader.getExtensionLoader(Shape.class);
        //根据key去获取对应的类
        Shape rect = extensionLoader.getExtension("rect");
        rect.draw();

        Shape circle = extensionLoader.getExtension("circle");
        circle.draw();

		//默认类,@SPI("circle")根据这个值获取
        Shape defaultExtension = extensionLoader.getDefaultExtension();
        defaultExtension.draw();

    }
}

输出结果
在这里插入图片描述

@Adaptive注解
注解加在类上
@Adaptive
public class Circle implements Shape {
    public void draw() {
        System.out.println("画一个圆");
    }
}

@Test
void test2() {
        ExtensionLoader<Shape> extensionLoader = ExtensionLoader.getExtensionLoader(Shape.class);
        Shape shape3 = extensionLoader.getAdaptiveExtension();
        shape3.draw();
    }

在这里插入图片描述

注解加在接口的方法上

注解加在接口的方法上,会动态生成Shape$Adaptive, 然后解析传入的URL参数,根据key值,调用对应的类的方法。

@SPI("circle")
public interface Shape {
    void draw();

	// 去解析url,从里面提取key=name的value值 对应的类
    @Adaptive("name")
    void draw(URL url);
}

public class Circle implements Shape {
    public void draw() {
        System.out.println("画一个圆");
    }

    public void draw(URL url) {
        System.out.println("画一个圆"+url);
    }
}

public class Rect implements Shape {

    public void draw() {
        System.out.println("画一个矩形");
    }

    public void draw(URL url) {
        System.out.println("画一个矩形"+url);
    }
}

测试类

 //Adaptive 在方法上
 @Test
  void test3() {
        ExtensionLoader<Shape> extensionLoader = ExtensionLoader.getExtensionLoader(Shape.class);
        Shape shape = extensionLoader.getAdaptiveExtension();
        // 设置name = circle ,Adaptive去获取对应circle的类,并调用
        URL url = URL.valueOf("dubbo://localhost/server?name=circle");
        shape.draw(url);
    }

断点查看shape的类型:
在这里插入图片描述
运行结果:
在这里插入图片描述

Spi应用
除了在Dubbo源码中大量运用spi之外,还能在其他应用中看到它的使用。
比如spring的web模块。
  1. 当web容器启动后,提供第三方应用一些初始化的操作。servlet规范中通过ServletContainerInitializer就可以实现此功能。
  2. spring中实现了ServletContainerInitializer这个类,并通过spi引导和加载自定义实现类,重写onStartup方法
  3. 并结合@HandlesTypes(WebApplicationInitializer.class)注解,在onStartup方法里注入该对象。
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值