美文网首页
Dubbo学习笔记(二) SPI

Dubbo学习笔记(二) SPI

作者: 云师兄 | 来源:发表于2019-11-03 23:55 被阅读0次

1. Java SPI

1.1 概念

SPI全称是Service Provider Interface,是JDK内置的一种服务提供发现功能,一种动态替换发现的机制。

1.2 规范

使用SPI需要遵循下面的规范:

  • 设置META-INF目录,并在下面新建一个services目录

  • 在上面创建的目录下,放置配置文件

  • 使用ServiceLoad.load()方法进行加载

1.3 示例

首先新建一个maven项目,结构如下: 1572792821854.png

下面分步骤进行描述。
首先新建一个HelloService接口:

public interface HelloInterface {
    public void sayHello();
}

以及该接口的两个实例:

public class ImageHello implements HelloInterface {
    public void sayHello() {
        System.out.println("Image hello!");
    }
}
public class TextHello implements HelloInterface {
    public void sayHello() {
        System.out.println("Text hello");
    }
}

然后在resources目录下的META-INF.services目录下新建一个配置文件,文件名要求是接口全路径名,内容是要实现的接口实现类:

com.spiexample.impl.ImageHello
com.spiexample.impl.TextHello

并且文件是UTF-8编码的。

最后在SPIMain这个启动类中进行测试:

public class SPIMain {
    public static void main(String[] args){
        ServiceLoader<HelloInterface> serviceLoader = ServiceLoader.load(HelloInterface.class);
        if (serviceLoader != null){
            for(HelloInterface helloInterface : serviceLoader){
                helloInterface.sayHello();
            }
        }
    }
}

最终输出结果为:

Image hello!
Text hello

说明已经成功创建出接口的两个实现类的对象并执行方法了。

2. Dubbo SPI

Dubbo SPI相比于Java SPI而言,做了一定的优化和改进。JDK标准的SPI会一次性实例化扩展点所有实现,如果有扩展实现则初始化很耗时,如果没有用上也加载,则浪费资源。如第一小节的例子中,HelloInterface接口有很多实现类,ServiceLoader.load方法返回的serviceLoader对象中封装了所有实现类的实例。所以ServiceLoader实现了Iterable接口,以遍历出所有的实现类。

Dubbo SPI则不然,它只加载配置文件中的类,并分成不同的种类缓存在内存中,而不会全部初始化,在性能上有更好的表现。

下面是一个例子,在第一小节的例子上通过Dubbo SPI进行改进。

首先修改接口类:

@SPI("impl")
public interface HelloInterface {
    public void sayHello();
}

添加了一个注解,并且设置属性为impl,表示接口默认实现为impl。

然后再定义一个这个接口的实现类:

public class NewHello implements HelloInterface {
    public void sayHello() {
        System.out.println("new hello!");
    }
}

然后在META-INF目录下新建一个dubbo目录,再新建一个文件,文件名也是要求是接口HelloInterface的全路径名,内容是:

impl=com.spiexample.impl.NewHello

impl即对应了接口的一个实现类。

写完这些后,最后main方法中调用如下:

HelloInterface helloInterface = ExtensionLoader.
  getExtensionLoader(HelloInterface.class).
  getDefaultExtension();
helloInterface.sayHello();

最终就成功打印new hello,说明调用实例的就是指定的NewHello。

相关文章

网友评论

      本文标题:Dubbo学习笔记(二) SPI

      本文链接:https://www.haomeiwen.com/subject/ygfrbctx.html