Redian新闻
>
深入理解java和dubbo的SPI机制

深入理解java和dubbo的SPI机制

公众号新闻

来源 | OSCHINA 社区

作者 | 京东云开发者-京东物流 龚航林

原文链接:https://my.oschina.net/u/4090830/blog/10116011

1 SPI 简介

1.1 SPI(Service Provider Interface)

本质:将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。
java SPI:用来设计给服务提供商做插件使用的。基于策略模式来实现动态加载的机制。我们在程序只定义一个接口,具体的实现交个不同的服务提供者;在程序启动的时候,读取配置文件,由配置确定要调用哪一个实现。
dubbo SPI:在 dubbo 中也有 SPI 机制,虽然都需要将接口全限定名配置在文件中,但是 dubbo 并没有使用 java 的 spi 机制,而是重新实现了一套功能更强的 SPI 机制,支持了 AOP 与依赖注入,并且 利用缓存提高加载实现类的性能,同时 支持实现类的灵活获取。基于 SPI,我们可以很容易的对 Dubbo 进行拓展。例如 dubbo 当中的 protocol,LoadBalance 等都是通过 SPI 机制扩展。

2 java SPI

2.1 实现过程

1)需要在 classpath 下创建一个目录,该目录命名必须是:META-INF/service
2)在该目录下创建一个 文本文件,该文件需要满足以下几个条件
  • 文件名必须是扩展的接口的全路径名称

  • 文件内部描述的是该扩展接口的所有实现类

  • 文件的编码格式是 UTF-8

3)通过 java.util.ServiceLoader 的加载机制来加载服务

2.2 工作原理

1)当调用 ServiceLoader.load (Class clz) 方法时,会到 jar 中中的目录 “META-INF/services/“ + clz.getName 进行文件读取,
2)当在调用 ServiceLoader.forEach () 方法时,实际走的是 LazyIterator,当在调用 LazyIterator.hasNext () 时,在文件中读取到实际的服务实现类并把它们通过调用 Class.forName (String name, boolean initialize,ClassLoader loader)。

2.3 实际应用

javaSPI 我们最熟悉的应用就是数据库驱动了,mysql 和 oracle 驱动针对 JDBC 分别有自己的实现,这就有赖于 java 的 SPI 机制。

3 dubbo SPI

3.1 实现过程

1)需要在 classpath 下创建一个目录,该目录命名可以是:META-INF/service/、META-INF/dubbo/、META-INF/dubbo/internal/
2)在该目录下创建一个 文本文件,该文件需要满足以下几个条件
  • 文件名必须是扩展的接口的全路径名称

  • 文件内部描述的是该扩展接口的所有实现类,将服务实现类写成 KV 键值对的形式,Key 是拓展类的 name,Value 是扩展的全限定名实现类。

3)通过 org.apache.dubbo.common.extension.ExtensionLoader 的加载机制来加载服务

3.2 工作原理

1)我们首先通过 ExtensionLoader 的 getExtensionLoader 方法获取一个接口的 ExtensionLoader 实例,然后再通过 ExtensionLoader 的 getExtension 方法获取拓展类对象,源码如下,首先是 getExtensionLoader 方法:
new ExtensionLoader (type) 源码如下:
注意这里创建 ExtensionLoader 对象的构造方法如下:ExtensionLoader.getExtensionLoader 获取 ExtensionFactory 接口的拓展类,再通过 getAdaptiveExtension 从拓展类中获取目标拓展类。
2)通过 ExtensionLoader.getExtensionLoader 取到接口的加载器 Loader 之后,再通过 getExtension 方法获取需要拓展类对象。
以上代码首先检查 holder 中的实例缓存,缓存未命中则创建拓展对象。dubbo 中包含了大量的扩展点缓存。这个就是典型的使用空间换时间的做法。
创建拓展类对象步骤分别为:
  1. 通过 getExtensionClasses 从配置文件中加载所有的拓展类,再通过名称获取目标拓展类

  2. 通过反射创建拓展对象

  3. 向拓展对象中注入依赖

  4. 将拓展对象包裹在相应的 Wrapper 对象中

我们接下来重点看下 getExtensionClasses 方法:
先从缓存中获取 class,缓存未命中则调用 loadExtensionClasses 方法加载,我们再看下 loadExtensionClasses 这个方法:
我们看到这里遍历调用了多个策略去加载 class 的,跟到这里我们发现非常有意思的是:dubbo 在加载 META-INF 目录下的 class 键值对的时候采用了 javaSPI 的方式
这里 dubbo 使用 javaSPI 的方式加载到 3 中类加载策略:
org.apache.dubbo.common.extension.DubboInternalLoadingStrategy 用于加载 META-INF/dubbo/internal/ 中的 class
org.apache.dubbo.common.extension.DubboLoadingStrategy 用于加载 META-INF/dubbo/ 中的 class
org.apache.dubbo.common.extension.ServicesLoadingStrategy 用于加载 META-INF/service/ 中的 class
dubbo 的 SPI 还提供了自适应(Adaptive)、自动注入的功能就不在这里过多展开了,有兴趣可以自行了解。

3.3 实际应用

dubbo 中大量使用了 SPI 机制:
例如 dubbo 的多协议的实现:

4 javaSPI 和 dubboSPI 对比

  1. Java SPI 在加载扩展点的时候,会一次性加载所有可用的扩展点,很多是不需要的,会浪费系统资源。dubboSPI 有选择性地加载所需要的 SPI 接口。

  2. javaSPI 配置文件中只是简单的列出了所有的扩展实现,而没有给他们命名。导致在程序中很难去准确的引用它们。而 dubboSPI 配置文件中以键值对的形式有别名,易于区分。

  3. SPI 扩展如果依赖其他的扩展,javaspi 做不到自动注入和装配,dubbo 可以实现自动注入。

  4. javaSPI 不提供类似于 Spring 的 IOC 和 AOP 功能,dubboSPI 是支持的

END



中国程序员在国内为海外软件公司工作,被没收违法所得100多万



这里有最新开源资讯、软件更新、技术干货等内容

点这里 ↓↓↓ 记得 关注✔ 标星⭐ 哦



微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
医药代表的真实故事 1 引言真的没想到!清华和DK联手,为中学生量身打造教辅...未来有望“不内卷也能进入理想学校”,听国家督学刘坚谈中高考改革趋势30万+笔记,68%毛利率,拆解Jellycat背后的生意与品牌逻辑没体会过这种深入骨髓的痛,你就无法真正理解为什么中国老百姓这么支持华为!又在同一天开赛!BBO&USABO如何双线夺金?留学生找工作be like:质疑BOSS,理解BOSS,成为BOSS......「细胞与基因疗法领域进入理性增长阶段」,Lonza总裁谈如何在低迷市场中提振CGT领域的发展机会NAND和DRAM,一起涨价质疑J人,理解J人,成为J人皮光毛亮的帅哥回来了!—— 回馈感谢篇神秘的大杂院 (五) 哺育之恩闺房里的桃子姐姐[家居][木工]Modified Split Top Roubo Style Mobile Workbench 自制可移动木工桌好喜欢COACH和Disney的联名!封面款现在5折!重磅!DoorDash、UberEats、Grubhub和Relay通通惨败2024年体育单招想考入理想院校文化需要多少分?又在同一天开赛!BBO & USABO如何双线夺金?奥运冠军炒股都亏了!2亿新中产陷入理财难题:到底该买啥?CIIE Watch | Sustainability in Spotlight: from Product to Booth基于 Dubbo,如何利用APISIX 构建跨网 RPC深入理解Flutter图片加载原理Uber Eats和DoorDash纽约顾客结账,小费提示取消《湖天一览楼》1部2章(2)吴玉棠中举KDD 2023 | WHEN异构时间序列分析模型:当Wavelet和DTW遇上Attention深入理解 Linux 的 I/O 系统【无忧买房】Cambridge全新四室公寓出售,今年新建,近Porter和Davis Square,周边生活条件非常好一图读懂 | EPA和DHA在心血管系统中的作用机制新闻第86期|深入了解CBAM:欧盟碳边境调节机制的制定与细则深入理解BigBird的块稀疏注意力推荐35款 SpringBoot/SpringCloud 开源项目,附源码给中国人最爱喝的饮料分级,你最爱的都是C和D深入理解线段树重磅!大批人失业!Uber、DoorDash和Grubhub败诉!价格上涨!深入理解 TCP;场景复现,掌握鲜为人知的细节
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。