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

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

3天内不再提示

Java中的SPI动态扩展(下)

jf_78858299 来源:码农参上 作者:Dr Hydra 2023-03-24 14:27 次阅读

4、服务发现

现在两个服务提供方都实现了接口,下面关键的一步就是服务发现,这一步java中的spi发现机制已经帮我们实现好了。

创建一个新项目aircondition-app,引入上面打好的两个jar包。

<dependencies>
    <dependency>
        <groupId>com.cn.hydra<span class="hljs-name"groupId>
        <artifactId>aircondition-hanging-type<span class="hljs-name"artifactId>
        <version>1.0-SNAPSHOT<span class="hljs-name"version>
    <span class="hljs-name"dependency>

    <dependency>
        <groupId>com.cn.hydra<span class="hljs-name"groupId>
        <artifactId>aircondition-vertical-type<span class="hljs-name"artifactId>
        <version>1.0-SNAPSHOT<span class="hljs-name"version>
    <span class="hljs-name"dependency>
<span class="hljs-name"dependencies>

按照上面的说法,虽然每个服务提供者对于接口都有不同的实现,但是作为调用者来说,它并不需要关心具体的实现类,我们要做的是通过接口来调用服务提供者实现的方法。

下面,就是关键的服务发现环节,我们写一个方法,根据型号去调用对应空调的开关方法。

public class AirconditionApp {
    public static void main(String[] args) {
        new AirconditionApp().turnOn("VerticalType");
    }

    public void turnOn(String type){
        ServiceLoader

测试结果:

图片

可以看到,测试过程中,通过定义的接口IAircondition发现了两个实现类,并通过参数,调用了特定实现类的某个方法。整段代码中没有出现过具体的服务实现类,操作都是通过接口调用。

5、原理

了解了spi的工作流程,我们再来看看它的实现,其实最关键的就是上面代码中出现的ServiceLoader这个类。

上面的示例代码中,对于ServiceLoaderload()方法的结果,我们用for循环进行了遍历,这一点我们看一下源码就能明白,因为ServiceLoader实现了Iterable这一接口,而整个服务发现的核心,就在它的iterator()方法中。

图片

注意这里面有两个关键的东西,找一下在源码中定义的地方:

图片

注释写的非常明白,providers就是一个缓存,在迭代器中如果先从这里面进行查找,如果里面有就继续往下找,没有了的话就用这个懒加载的lookupIterator查找。

那么就简单了,接着往下看LazyIterator,看看它里面的hasNext()next()两个方法是怎么实现的。

图片

这个acc是一个安全管理器,在前面通过System.getSecurityManager()判断并赋值,debug看一下这里都是null,所以直接看hasNextService()nextService()方法就可以了。

hasNextService()方法中,会取出接口取出实现类的类名放到nextName中:

图片

接下来,在nextService()方法中,则会先加载这个实现类,然后实例化对象,最终放入缓存中去。

图片

在迭代器的迭代过程中,会完成所有实现类的实例化,其实归根结底,还是基于java反射去实现的。

6、应用

要说spi的实际应用,大家最常见的应该就是日志框架slf4j了,它利用spi实现了插槽式接入其他具体的日志框架。

说白了,slf4j本身就是个日志门面,并不提供具体的实现,需要绑定其他具体实现才能真正的引入日志功能。

例如我们可使用log4j2作为具体的绑定器,只需要在pom中引入slf4j-log4j12,就可以使用具体功能。

org.slf4j
    slf4j-api
    2.0.3


    org.slf4j
    slf4j-log4j12
    2.0.3

引入项目后,点开它的jar包看一下具体结构:

图片

有没有发现一个彩蛋,先说为什么我们pom中引入的明明是slf4j-log4j12,实际上引入的是slf4j-reload4j?翻一下官网的文档:

图片

大意就是在2015年和2022年,log4j1.x就已经宣布end of life终止了,原因也不难猜,估计是因为频繁爆出的漏洞。在那之后,slf4j-log4j在构建阶段就会自动重定向到slf4j-reload4j了,并且官方也强烈建议使用slf4j-reload4j作为替代。

再回头看一下jar包的META-INF.services里面,通过spi注入了Reload4jServiceProvider这个实现类,它实现了SLF4JServiceProvider这一接口,在它的初始化方法initialize()中,会完成初始化等工作,后续可以继续获取到LoggerFactoryLogger等具体日志对象。

7、总结

Java中的SPI提供了一种比较特别的服务发现和调用机制,通过接口灵活的将服务调用与服务提供者分离,用于提供给第三方实现扩展时还是很方便的。但是也有缺点,比方说一旦加载一个接口,就会把所有实现类都加载进来,可能会加载到不需要的冗余服务。不过站在整体角度上,还是给我们提供了一种非常不错的框架扩展、集成的思路。

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

    关注

    19

    文章

    2967

    浏览量

    104750
  • SPI
    SPI
    +关注

    关注

    17

    文章

    1706

    浏览量

    91581
  • 代码
    +关注

    关注

    30

    文章

    4788

    浏览量

    68611
  • spring
    +关注

    关注

    0

    文章

    340

    浏览量

    14343
收藏 人收藏

    评论

    相关推荐

    AG32 SPI扩展使用

    platformio.ini 的 logic 选项: C. 生成 logic 出来(点 prepare LOGIC): D. 复制上边准备好的 full_duplex_spi.v,覆盖掉 logic 刚生成
    发表于 05-28 11:19

    聊聊Dubbo - Dubbo可扩展机制实战

    是对Dubbo的扩展机制有一个基本的了解。如果对Java SPI比较了解的同学,可以跳过。Java SPI(Service Provider
    发表于 06-04 17:33

    嵌入式Linux系统内核抽象的动态扩展技术

    运行时由JVM(Java VirtualMachine)动态地加载。Liao等人在1996年提出,将JVM插入到微内核,从而可以让用户编写Java程序,以
    发表于 10-26 09:22

    嵌入式Linux系统内核抽象的动态扩展技术

    运行时由JVM(Java VirtualMachine)动态地加载。Liao等人在1996年提出,将JVM插入到微内核,从而可以让用户编写Java程序,以
    发表于 10-28 09:53

    嵌入式Linux系统内核抽象的动态扩展技术

    嵌入式Linux系统内核抽象的动态扩展技术随着嵌入式技术的快速发展和嵌入式设备的普及,嵌入式应用发展的一个关键趋势是从静态的、固定的系统功能到动态的、可
    发表于 04-04 17:12

    java动态代理机制和作用

    的我们的功能,我们更需要学习的是其底层是怎么样的一个原理,而AOP的原理就是java动态代理机制,所以本篇随笔就是对java动态机制进行一个回顾。 在
    发表于 09-27 14:37 0次下载

    java动态代理分析

    定义:为其他对象提供一种代理以控制对这个对象的访问。 动态代理使用 java动态代理机制以巧妙的方式实现了代理模式的设计理念。 代理模式示例代码 publicinterfaceSubject
    发表于 09-27 15:14 0次下载

    英创信息技术JAVA操作英创主板SPI接口简介

    2017年9月,英创在Linux的文件系统移植了针对嵌入式Linux的JRE(Java Runtime Environment),能够支持Java应用程序的运行。由于Java语言不能
    的头像 发表于 02-06 11:09 1927次阅读
    英创信息技术<b class='flag-5'>JAVA</b>操作英创主板<b class='flag-5'>SPI</b>接口简介

    Java实验:类和对象的扩展

    Java实验:类和对象的扩展
    发表于 07-08 15:36 20次下载
    <b class='flag-5'>Java</b>实验:类和对象的<b class='flag-5'>扩展</b>

    源码级深度理解Java SPI

    SPI 配置:Java SPI 机制约定的配置文件,提供查找服务实现类的逻辑。配置文件必须置于 META-INF/services 目录,并且,文件名应与服务提供者接口的完全限定名保
    的头像 发表于 11-15 11:38 665次阅读

    基于spring的SPI扩展机制是如何实现的?

    基本上,你一说是基于 spring 的 SPI 扩展机制,再把spring.factories文件和EnableAutoConfiguration提一,那么这个问题就答的八九不离十了。
    的头像 发表于 03-07 09:17 1053次阅读

    JavaSPI动态扩展(上)

    基本上,你一说是基于spring的SPI扩展机制,再把`spring.factories`文件和`EnableAutoConfiguration`提一,那么这个问题就答的八九不离十了。
    的头像 发表于 03-24 14:27 467次阅读
    <b class='flag-5'>Java</b><b class='flag-5'>中</b>的<b class='flag-5'>SPI</b><b class='flag-5'>动态</b><b class='flag-5'>扩展</b>(上)

    Java、Spring、Dubbo三者SPI机制的原理和区别

    其实我之前写过一篇类似的文章,但是这篇文章主要是剖析dubbo的SPI机制的源码,中间只是简单地介绍了一Java、Spring的SPI机制,并没有进行深入,所以本篇就来深入聊一聊这三
    的头像 发表于 06-05 15:21 1039次阅读
    <b class='flag-5'>Java</b>、Spring、Dubbo三者<b class='flag-5'>SPI</b>机制的原理和区别

    SPI是什么?Java SPI的使用介绍

    SPI 全称 Service Provider Interface,是 Java 提供的一套用来被第三方实现或者扩展的 API,它可以用来启用框架扩展和替换组件。
    的头像 发表于 09-02 09:58 1393次阅读
    <b class='flag-5'>SPI</b>是什么?<b class='flag-5'>Java</b> <b class='flag-5'>SPI</b>的使用介绍

    java本身自带的SPI扩展机制是怎么一回事?

    八股文背多了,相信大家都听说过一个词,SPI 扩展
    的头像 发表于 01-02 10:32 688次阅读
    <b class='flag-5'>java</b>本身自带的<b class='flag-5'>SPI</b><b class='flag-5'>扩展</b>机制是怎么一回事?