0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

JDK内置的一种服务SPI机制

jf_ro2CN3Fa 来源:稀土掘金 2023-02-15 09:15 次阅读

SPI(Service Provider Interface)是JDK内置的一种服务提供发现机制,可以用来启用框架扩展和替换组件,主要用于框架中开发,例如Dubbo、Spring、Common-Logging,JDBC等采用采用SPI机制,针对同一接口采用不同的实现提供给不同的用户,从而提高了框架的扩展性。

Java SPI实现

Java内置的SPI通过java.util.ServiceLoader类解析classPath和jar包的META-INF/services/目录 下的以接口全限定名命名的文件,并加载该文件中指定的接口实现类,以此完成调用。

示例说明

创建动态接口

publicinterfaceVedioSPI
{
voidcall();
}

实现类1

publicclassMp3VedioimplementsVedioSPI
{
@Override
publicvoidcall()
{
System.out.println("thisismp3call");
}

}

实现类2

publicclassMp4VedioimplementsVedioSPI
{
@Override
publicvoidcall()
{
System.out.println("thisismp4call");
}

}

在项目的source目录下新建META-INF/services/目录下,创建com.skywares.fw.juc.spi.VedioSPI文件。

2dc32b86-ac5d-11ed-bfe3-dac502259ad0.png

相关测试

publicclassVedioSPITest
{
publicstaticvoidmain(String[]args)
{
ServiceLoaderserviceLoader=ServiceLoader.load(VedioSPI.class);

serviceLoader.forEach(t->{
t.call();
});
}
}

说明:Java实现spi是通过ServiceLoader来查找服务提供的工具类。

运行结果:

2dd556f8-ac5d-11ed-bfe3-dac502259ad0.png

源码分析

上述只是通过简单的示例来实现下java的内置的SPI功能。其实现原理是ServiceLoader是Java内置的用于查找服务提供接口的工具类,通过调用load()方法实现对服务提供接口的查找,最后遍历来逐个访问服务提供接口的实现类。

2de67e92-ac5d-11ed-bfe3-dac502259ad0.png

从源码可以发现:

ServiceLoader类本身实现了Iterable接口并实现了其中的iterator方法,iterator方法的实现中调用了LazyIterator这个内部类中的方法,迭代器创建实例。

所有服务提供接口的对应文件都是放置在META-INF/services/目录下,final类型决定了PREFIX目录不可变更。

虽然java提供的SPI机制的思想非常好,但是也存在相应的弊端。具体如下:

Java内置的方法方式只能通过遍历来获取

服务提供接口必须放到META-INF/services/目录下。

针对java的spi存在的问题,Spring的SPI机制沿用的SPI的思想,但对其进行扩展和优化。

Spring SPI

Spring SPI沿用了Java SPI的设计思想,Spring采用的是spring.factories方式实现SPI机制,可以在不修改Spring源码的前提下,提供Spring框架的扩展性。

Spring 示例

定义接口

publicinterfaceDataBaseSPI
{
voidgetConnection();
}

相关实现

##DB2实现
publicclassDB2DataBaseimplementsDataBaseSPI
{
@Override
publicvoidgetConnection()
{
System.out.println("thisdatabaseisdb2");
}

}

##Mysql实现
publicclassMysqlDataBaseimplementsDataBaseSPI
{
@Override
publicvoidgetConnection()
{
System.out.println("thisismysqldatabase");
}

}

1、在项目的META-INF目录下,新增spring.factories文件

2df71af4-ac5d-11ed-bfe3-dac502259ad0.png

2、填写相关的接口信息,内容如下:

com.skywares.fw.juc.springspi.DataBaseSPI=com.skywares.fw.juc.springspi.DB2DataBase,com.skywares.fw.juc.springspi.MysqlDataBase

说明多个实现采用逗号分隔。

相关测试类

publicclassSpringSPITest
{
publicstaticvoidmain(String[]args)
{
ListdataBaseSPIs=SpringFactoriesLoader.loadFactories(DataBaseSPI.class,
Thread.currentThread().getContextClassLoader());

for(DataBaseSPIdatBaseSPI:dataBaseSPIs){
datBaseSPI.getConnection();
}
}
}

输出结果

2e061d9c-ac5d-11ed-bfe3-dac502259ad0.png

从示例中我们看出,Spring 采用spring.factories实现SPI与java实现SPI非常相似,但是spring的spi方式针对java的spi进行的相关优化具体内容如下:

Java SPI是一个服务提供接口对应一个配置文件,配置文件中存放当前接口的所有实现类,多个服务提供接口对应多个配置文件,所有配置都在services目录下;

Spring factories SPI是一个spring.factories配置文件存放多个接口及对应的实现类,以接口全限定名作为key,实现类作为value来配置,多个实现类用逗号隔开,仅spring.factories一个配置文件。

那么spring是如何通过加载spring.factories来实现SpI的呢?我们可以通过源码来进一步分析。

源码分析

2e1b1332-ac5d-11ed-bfe3-dac502259ad0.png

说明:loadFactoryNames解析spring.factories文件中指定接口的实现类的全限定名,具体实现如下:

2e312384-ac5d-11ed-bfe3-dac502259ad0.png

说明:获取所有jar包中META-INF/spring.factories文件路径,以枚举值返回。遍历spring.factories文件路径,逐个加载解析,整合factoryClass类型的实现类名称,获取到实现类的全类名称后进行类的实例话操作,其相关源码如下:

2e4bdbb6-ac5d-11ed-bfe3-dac502259ad0.png

说明:实例化是通过反射来实现对应的初始化。







审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • JAVA
    +关注

    关注

    19

    文章

    2954

    浏览量

    104511
  • SPI
    SPI
    +关注

    关注

    17

    文章

    1696

    浏览量

    91274
  • JDBC
    +关注

    关注

    0

    文章

    25

    浏览量

    13389

原文标题:深入剖析 Spring Boot 的 SPI 机制

文章出处:【微信号:芋道源码,微信公众号:芋道源码】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    请问板子的延迟函数是一种什么机制

    我想请问下,你们板子的延迟函数是一种什么机制,如以上的定义所示,他的延时单位是ms还是其他,就像Delay(0x000FFFFF)算是延时了多少秒?有没有相关的资料视屏什么的讲解
    发表于 10-15 10:40

    怎样去设计一种同步补偿机制(CDCO算法)?

    本文基于发送方接收方双向同步算法的原理,提出一种基于时钟漂移与偏移的同步补偿机制(CDCO算法)。
    发表于 05-17 06:18

    分享一种高性能的FM内置天线解决方案

    分享一种高性能的FM内置天线解决方案
    发表于 05-26 06:18

    如何去实现一种SPI接口电路?

    SPI总线协议是什么?如何去实现一种SPI接口电路?
    发表于 05-28 07:08

    是否有一种机制可以从虚拟功能处理程序进行屏幕转换呢?

    我想知道是否有一种机制可以根据在滚动列表控件(小部件)上选择的项目转换到不同的屏幕,并传递有关所选项目或所选滚动列表项目的索引的信息,或者是否有一种机制可以从虚拟功能处理程序进行屏幕转
    发表于 12-13 08:09

    一种基于最优网格的动态数据过滤机制

    数据过滤机制是数据分发管理的核心,直接影响数据分发管理效率。该文提出一种基于最优网格的动态数据过滤机制,分析网格单元大小与更新区域网格数量、冗余信息数量的关系
    发表于 04-14 09:06 18次下载

    一种高效的磁盘队列I/O机制

    分析了传统磁盘队列的存储管理开销和读写性能,针对磁盘队列I/O已成为影响消息服务器性能的首要瓶颈,提出了一种高效磁盘队列I/O机制—FlashQ。FlashQ采用物理上连续的磁盘块
    发表于 05-14 19:51 32次下载

    AVR 单片机SPI 通信的一种抗干扰方法

    AVR 单片机SPI 通信的一种抗干扰方法
    发表于 05-15 16:03 44次下载

    一种基于市场机制的随机服务系统模型

             在市场机制的网格环境中对大量的用户进行有效的排队是很有必要的。本文以随机服务系统理论为基础针对网格计算提出了一种基于市场
    发表于 09-05 08:48 16次下载

    一种ad hoc网信任声誉评估机制

    在Ad hoc 网络中,设计一种有效的机制来确保信息包的有效传递是研究重点。本文提出了一种信任声誉评估机制,不同于以往根据位置评估声誉和处理恶意节点散播虚假声誉的
    发表于 09-22 10:24 5次下载

    SPI模式下MMC卡的读写机制

    SPI模式下MMC卡的读写机制  多媒体卡MMC(MultiMedia Card)是由美国SanDisk公司和德国Simens公司于1997年共同开发的一种多功能Flash存储设备。基于ARM7芯
    发表于 03-29 15:13 1172次阅读
    <b class='flag-5'>SPI</b>模式下MMC卡的读写<b class='flag-5'>机制</b>

    一种通用SPI接口的FPGA设计与实现

    SPI 串行总线是一种常用的标准接口,其使用简单方便而且占用系统资源少,应用相当广泛。本文将介绍一种新的通用的SPI 总线的FPGA 实现方法。
    发表于 09-09 11:58 67次下载
    <b class='flag-5'>一种</b>通用<b class='flag-5'>SPI</b>接口的FPGA设计与实现

    一种改进的区块链共识机制的研究与实现

    区块链作为比特币的底层技术,是一种通过去中心化、去信任的方式集体维护个可靠数据库的技术方案。共识机制是区块链的核心,解决了如何在个缺乏信任、完全自由开放的网络中达成共识的问题。 文
    发表于 01-10 14:24 1次下载
    <b class='flag-5'>一种</b>改进的区块链共识<b class='flag-5'>机制</b>的研究与实现

    可插拔组件设计机制SPI介绍

    SPI 的全称是 Service Provider Interface, 即提供服务接口;是一种服务发现机制
    的头像 发表于 03-23 09:20 1133次阅读

    什么是SPI机制

    一种服务提供发现接口机制,旨在由第三方服务实现或扩展为组件,方便开发人员快速集成指定扩展组件满足指定的需求。这
    的头像 发表于 10-08 15:03 1074次阅读
    什么是<b class='flag-5'>SPI</b><b class='flag-5'>机制</b>