在Duboo剖析-整体架构分析中介绍了dubbo中除了Service 和 Config 层为 API外,其他各层均为SPI,为SPI意味着下面各层都是组件化可以被替换的,这也是dubbo比较好的一点。
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 的扩展点加载是基于JDK 标准的 SPI 扩展点发现机制增强而来的,Dubbo 改进了 JDK 标准的 SPI 的以下问题:
下面看看Dubbo增强的SPI实现的时序图:
image.png
本文简单的介绍了Dubbo中SPI实现原理,更详尽的解析 敬请期待