Dubbo剖析-增强SPI的实现

一、前言

在Duboo剖析-整体架构分析中介绍了dubbo中除了Service 和 Config 层为 API外,其他各层均为SPI,为SPI意味着下面各层都是组件化可以被替换的,这也是dubbo比较好的一点。

二、JDK中标准SPI

JDK 中的 SPI(Service Provider Interface)是面向接口编程的,服务规则提供者会在 JRE 的核心 API 里面提供服务访问接口,而具体实现则由其他开发商提供。

例如规范制定者在rt.jar包里面定义了 数据库 的驱动接口 java.sql.Driver。 MySQL 实现的 Jar,如下:

screenshot.png
public class com.mysql.jdbc.Driver extends com.mysql.jdbc.NonRegisteringDriver implements java.sql.Driver

下面我们写个测试代码,看看具体是如何工作的。

    public static void main(String[] args) {
               //(1)
        ServiceLoader<Driver> loader = ServiceLoader.load(Driver.class);
               //(2)
        Iterator<Driver> iterator = loader.iterator();
        while (iterator.hasNext()) {
            Driver driver = (Driver) iterator.next();
            System.out.println("driver:" + driver.getClass() + ",loader:" + driver.getClass().getClassLoader());
        }
        //(3)
        System.out.println("current thread contextloader:" + Thread.currentThread().getContextClassLoader());
               //(4)
        System.out.println("ServiceLoader loader:" + ServiceLoader.class.getClassLoader());
    }

}

然后引入 MySQL 驱动的 Jar 包,执行结果如下。

driver:class com.mysql.jdbc.Driver,loader:sun.misc.Launcher$AppClassLoader@4554617c
current thread contextloader:sun.misc.Launcher$AppClassLoader@4554617c
ServiceLoader loader:null

可知找到了mysql的驱动,如果你在引入Oracle的驱动的jar包后在运行,则会输出找到了mysql和Oracle的驱动,这也说明了,JDK标准的SPI会同时把spi接口的所有的实现类都提前加载好。

关于JDK中SPI的原理和具体使用可以参考 Java 类加载器揭秘 中
一种特殊的类加载器 ContextClassLoader 章节。

三、Dubbo增强的SPI

Dubbo 的扩展点加载是基于JDK 标准的 SPI 扩展点发现机制增强而来的,Dubbo 改进了 JDK 标准的 SPI 的以下问题:

  • JDK 标准的 SPI 会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源。
  • 如果扩展点加载失败,就失败了,给用户没有任何通知。比如:JDK 标准的ScriptEngine,如果Ruby ScriptEngine 因为所依赖的 jruby.jar 不存在,导致 Ruby ScriptEngine 类加载失败,这个失败原因被吃掉了,当用户执行 ruby 脚本时,会报空指针异常,而不是报Ruby ScriptEngine不存在。
  • 增加了对扩展点 IoC 和 AOP 的支持,一个扩展点可以直接 setter 注入其它扩展点。

下面看看Dubbo增强的SPI实现的时序图:

image.png
  • 其中代码(1)获取当前SPI接口对应的ExtensionLoader
  • 代码(2)获取适配器实例,内部首先获取该spi对应的所有实现类的Class对象,然后创建适配器实例,最后注入该适配器依赖的其他扩展点。
  • 代码(8)根据名称获取具体的spi实现类,内部是创建一个实现类的实例,并使用warp类进行包装后返回。

四、总结

本文简单的介绍了Dubbo中SPI实现原理,更详尽的解析 欢迎大家加入知识星球进行探讨。

121.png

在知识星球里面我们会深入讨论Java并发编程,以及JUC包源码;Java类加载器原理;Spring,Springboot,Tomcat,Dubbo等开源框架的使用以及源码剖析;分享作者从毕业到现在一路走来的学习经验,如何高效学习,如何阅读源码;讨论职业面试时候会经常遇到的问题以及如何作答,读者可以识别下面二维码加入:

121、.png

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: Dubbo剖析-增强SPI的实现

加多

加多

Java 攻城狮 at 阿里巴巴
加多,目前就职于阿里巴巴,热衷并发编程、ClassLoader,Spring等开源框架,分布式RPC框架dubbo,springcloud等;爱好音乐,运动。微信公众号:技术原始积累。知识星球账号:技术原始积累
加多
FavoriteLoading添加本文到我的收藏
  • Trackback are closed
  • Comments (0)
  1. No comments yet.

You must be logged in to post a comment.

return top