JDK SPI与Dubbo SPI的实现

- 日理万妓 2023-05-31 10:16 72阅读 0赞

JDK SPI

SPI全称Service Provider Interface,是提供厂商做插件开发的,如数据库驱动。

Java SPI使用了策略模式,一个接口多种实现。同时具体实现不在程序中指定,而是在程序之外的配置文件配置。

具体实现过程:

  1. 新建一个名称为driver的maven工程,定义一个DatabaseDriver接口及对应的方法,打成jar包,供后续实现依赖

    public interface DatabaseDriver {

    1. String buildConection(String msg);

    }

  2. 新建一个名称为mysql-driver的maven工程,在pom中引入driver工程的依赖,然后创建DatabaseDriver的实现类

    public class MysqlDriver implements DatabaseDriver {

    1. @Override
    2. public String buildConection(String msg) {
    3. return "MySQL Driver:" + msg;
    4. }

    }

  3. 在mysql-driver工程main文件夹下创建资源文件夹resources,然后再创建目录META-INF/services,在该目录下创建以要实现接口全路径命名的文件:如com.xxx.spi.DatabaseDriver,文件内容为接口的实现的全路径名:com.xxx.spi.MysqlDriver

  4. 新建一个名称为java-spi-test的工程,在pom中加入前面两个项目的依赖,可通过以下方式调用具体实现:

    public static void main( String[] args ) {

    1. ServiceLoader<DatabaseDriver> serviceLoader = ServiceLoader.load(DatabaseDriver.class);
    2. for (DatabaseDriver databaseDriver : serviceLoader) {
    3. System.out.println(databaseDriver.buildConection("hello"));
    4. }

    }

最后输出:MySQL Driver:hello

由此可以看出main方法中通过java.util.ServiceLoader可以获得接口的所有实现,具体使用哪种实现由用户决定。

Dubbo SPI

Dubbo 的扩展点机制是在 JDK SPI 机制上做了改进,引用官网的一段话:

Dubbo 改进了 JDK 标准的 SPI 的以下问题:

  • JDK 标准的 SPI 会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源。
  • 如果扩展点加载失败,连扩展点的名称都拿不到了。比如:JDK 标准的 ScriptEngine,通过 getName() 获取脚本类型的名称,但如果 RubyScriptEngine 因为所依赖的 jruby.jar 不存在,导致 RubyScriptEngine 类加载失败,这个失败原因被吃掉了,和 ruby 对应不起来,当用户执行 ruby 脚本时,会报不支持 ruby,而不是真正失败的原因。
  • 增加了对扩展点 IoC 和 AOP 的支持,一个扩展点可以直接 setter 注入其它扩展点。

约定:

在扩展类的 jar 包内,在资源路径META-INF/dubbo(或META-INF/services、META-INF/dubbo/internal)下放置扩展点配置文件,文件名称为接口全限定名且无后缀,文件内容为:配置名=扩展实现类全限定名,多个实现类用换行符分隔。

如果要定义dubbo SPI接口,需要在接口上添加@SPI注解,value为默认实现。

  1. @SPI("dubbo")
  2. public interface Protocol {
  3. int getDefaultPort();
  4. @Adaptive
  5. <T> Exporter<T> export(Invoker<T> var1) throws RpcException;
  6. @Adaptive
  7. <T> Invoker<T> refer(Class<T> var1, URL var2) throws RpcException;
  8. void destroy();
  9. }

以实现org.apache.dubbo.rpc.Protocol接口为例:

  1. 首先定义实现类com.xxx.dubbo.spi.impl.MyProtocolImpl

    public class MyProtocolImpl implements Protocol {

    1. @Override
    2. public int getDefaultPort() {
    3. return 8888;
    4. }
    5. @Override
    6. public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    7. return null;
    8. }
    9. @Override
    10. public <T> Invoker<T> refer(Class<T> aClass, URL url) throws RpcException {
    11. return null;
    12. }
    13. @Override
    14. public void destroy() {
    15. }

    }

  2. 然后在resources/META-INF/dubbo(或META-INF/services、META-INF/dubbo/internal)目录下创建名称为org.apache.dubbo.rpc.Protocol的配置文件(接口的全限定名)

配置文件内容为:myprotocol=com.xxx.dubbo.spi.impl.MyProtocolImpl(key=value方式)

  1. 最后可以通过以下方式调用dubbo的SPI实现类:

    public static void main(String[] args) {

    1. Protocol myprotocol = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("myprotocol");
    2. // 输出实现类中的端口号8888
    3. System.out.println(myprotocol.getDefaultPort());

    }

发表评论

表情:
评论列表 (有 0 条评论,72人围观)

还没有评论,来说两句吧...

相关阅读

    相关 JDK SPI

    [最近学习了JDK SPI][JDK SPI]   JDK SPI是什么 最近工作中听几个同事说了好几次SPI这个名词,虽然和我没关系,但是心里默默想还是学习一下,不

    相关 jdkdubboSPI机制

    [jdk和dubbo的SPI机制][jdk_dubbo_SPI] 前言:开闭原则一直是软件开发领域中所追求的,开闭原则中的"开"是指对于组件功能的扩展是开放的,是允许对其

    相关 Dubbo SPI

    前言 前面已经讲过[JDK SPI][], dubbo SPI主要基于JDK SPI机制,进行了增强,实现可扩展 为什么不直接用JDK的SPI呢,主要有哪些改变