iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >java中的spi怎么用
  • 419
分享到

java中的spi怎么用

2023-06-29 06:06:13 419人浏览 独家记忆
摘要

这篇文章主要介绍了java中的spi怎么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。前言在开发过程中,经常要用到第三方提供的SDK来完成一些业务扩展功能,比如调用第三方的

这篇文章主要介绍了java中的spi怎么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

    前言

    开发过程中,经常要用到第三方提供的SDK来完成一些业务扩展功能,比如调用第三方的发短信、图片验证码、人脸识别等等功能,但问题是,第三方SDK只是提供了标准的功能实现,某些场景下,开发者还想基于这些SDK做一些个性化的定制和扩展,那要怎么办呢?

    于是,一些优秀的SDK就通过SPI的机制,将一些接口扩能开放出来,开发者就可以基于这些SPI接口做自身的业务扩展了;

    总结一下SPI思想:在系统的各个模块中,往往有不同的实现方案,例如日志模块的方案、xml解析的方案等,为了在装载模块的时候不具体指明实现类,我们需要一种服务发现机制,java spi就提供这样一种机制。有点类似于ioc的思想,将服务装配的控制权移到程序之外,在模块化设计时尤其重要

    Java 的SPI机制在很多框架中间件等都有着广泛的使用,如SpringBootdubbo中均有采用,属于高级Java开发知识点,有必要掌握

    下面用一张简图说明下SPI机制的原理

    java中的spi怎么用

    一、jdk中SPI的使用规范

    • 定义通用的服务接口,针对服务接口,提供具体实现类

    • jar包的META-INF/services/目录中,新建一个文件,文件名为 接口的 “全限定名”, 文件内容为该接口的具体实现类的 “全限定名”

    • 将spi所在jar放在主程序的classpath中

    • 服务调用方用java.util.ServiceLoader,用服务接口为参数,去动态加载具体的实现类到JVM

    案例展示

    案例业务背景:

    • 提供一个统一的支付接口

    • 有两种支付方式,分别为支付宝支付和微信支付,实际中为不同支付厂商提供的SDK

    • 客户端为customer工程,即调用支付SDK的使用者

    java中的spi怎么用

    从工程的结构来看,也是遵循SPI的服务规范的,即在resources目录下,创建一个指定名称的文件夹,将接口实现的全限定名放进去,那么客户端只需要依赖特定的SDK,然后通过 serviceLoader的方式即可加载到依赖的SDK的服务

    客户端customer工程导入依赖

    <dependencies>        <dependency>            <artifactId>service-common</artifactId>            <groupId>com.congge</groupId>            <version>1.0-SNAPSHOT</version>        </dependency>        <dependency>            <artifactId>ali-pay</artifactId>            <groupId>com.congge</groupId>            <version>1.0-SNAPSHOT</version>        </dependency>        <dependency>            <artifactId>wechat-pay</artifactId>            <groupId>com.congge</groupId>            <version>1.0-SNAPSHOT</version>        </dependency>    </dependencies>
    public class MainTest {    public static void main(String[] args) {        ServiceLoader<PayService> loader = ServiceLoader.load(PayService.class);        loader.forEach(payService ->{            System.out.println(payService);            payService.pay();            System.out.println("=======");        });    }}

    运行下这段客户端的测试程序

    java中的spi怎么用

    我们不妨来看看serviceLoader中的一段关键代码,即加载服务接口时,可以发现,该方法最终要去找接口的实现类所在jar包下的 “META-INF/services” 目录中的服务实现,如果找到了就能被加载和使用

    java中的spi怎么用

    java中的spi怎么用

    SPI优点

    • 使用Java SPI机制的优势是实现解耦,使得第三方服务模块的装配控制的逻辑与调用者的业务代码分离

    • 应用程序可根据实际业务情况启用框架扩展或替换框架组件

    SPI缺点

    • srviceLoader 只能通过遍历全部获取,也就是接口的实现类全部加载并实例化一遍

    • 如果并不想用某些实现类,它也被加载并实例化了,这就造成了浪费

    • 获取某个实现类的方式不够灵活,只能通过Iterator形式获取,不能根据某个参数来获取对应的实现类

    • 多个并发多线程使用ServiceLoader类的实例是不安全的,需要加控制

    SPI机制在实际生产中的一个应用

    在小编的实际项目开发中,有这样一个需求,标准产品针对单点登录提供了多种实现,比如 基于cas方案,ldap方案,oauth3.0方案等,针对每种方案,提供了一套具体的实现,即封装成了各自的jar包

    标准产品在出厂并在客户端安装的时候,会有一套默认的实现,即oauth3.0实现,但是客户方有时候有自己的一套,比如cas服务器,那么客户希望能够对接cas单点登录,这么以来,具体到项目在实际部署的时候,就需要现场做一些特定的参数配置,将标准实现切换为 cas的实现即可,那么问题来了,标准产品是如何根据参数配置做到的呢?

    其实也很简单,就是使用了 serviceLoader机制,自动发现标准产品中能够加载到的所有单点登录实现,如果没有外部配置参数传入,则默认使用oauth3.0的实现,否则,将会采用外部参数传过来的那个实现。

    二、DUbbo 中SPI的使用

    可以说,dubbo框架是对spi使用的一个很好的例子,dubbo框架本身就是基于SPI规范做了更进一步的封装,从上面的优缺点分析中,我妈了解了原生的SPI在客户端选择服务的时候需要遍历所有的接口实现,比较浪费资源,而dubbo在此基础上有了更好的封装和实现,下面来了解下dubbo的SPI使用吧

    Dubbo 的 SPI 规范是:

    接口名:可随意定义

    实现类名:在接口名前添加一个用于表示自身功能的“标识前辍”字符串

    提供者配置文件路径:在依次查找的目录为

    • META-INF/dubbo/internal

    • META-INF/dubbo

    • META-INF/services

    提供者配置文件名称:接口的全限定性类名,无需扩展名

    提供者配置文件内容:文件的内容为 key=value 形式,value 为该接口的实现类的全限类性类名,key 可以随意,但一般为该实现类的“标识前辍”(首字母小写)。一个类名占 一行

    提供者加载:ExtensionLoader 类相当于 JDK SPI 中的 ServiceLoader 类,用于加载提供者配置文件中所有的实现类,并创建相应的实例

    Dubbo 的 SPI 举例

    创建一个Maven工程,并导入核心依赖

    <dependency>            <groupId>org.apache.dubbo</groupId>            <artifactId>dubbo</artifactId>            <version>3.0.0</version>        </dependency>        <dependency>            <groupId>junit</groupId>            <artifactId>junit</artifactId>            <version>4.12</version>        </dependency>

    定义 SPI 接口

    比如这里有一个下单的接口,注意接口上需要加上@SPI 注解 ,注解里面的值可以填,也可以不用填,如果填,请注意和配置文件里面的key值名称保持一致,填写了的话,加载的时候,会默认找这个key对应的实现

    @SPI("alipay")public interface Order {    String way();}

    定义两个接口的实现类

    public class AlipayOrder implements Order{    public String way() {        System.out.println("使用支付宝支付");        return "支付宝支付";    }}
    public class WechatOrder implements Order {    public String way() {        System.out.println("微信支付");        return "微信支付";    }}

    定义扩展类配置文件

    java中的spi怎么用

    alipay=com.congge.spi.AlipayOrderwechat=com.congge.spi.WechatOrder

    测试方法

    @Test    public void test1(){        ExtensionLoader<Order> extensionLoader = ExtensionLoader.getExtensionLoader(Order.class);        Order alipay = extensionLoader.getExtension("alipay");        System.out.println(alipay.way());        Order wechat = extensionLoader.getExtension("wechat");        System.out.println(wechat.way());    }

    java中的spi怎么用

    如果不指定加载哪个,而且接口配置了默认值,这里只需要在getExtension中设置 “true”,就会自动加载默认的那个

    java中的spi怎么用

    在Dubbo源码中,很多地方会存在下面这样的三种代码,分别是自适应扩展点、指定名称的扩展点、激活扩展点,dubbo通过这些扩展的spi接口实现众多的插拔式功能

    ExtensionLoader.getExtensionLoader(xxx.class).getAdaptiveExtension();ExtensionLoader.getExtensionLoader(xxx.class).getExtension(name);ExtensionLoader.getExtensionLoader(xxx.class).getActivateExtension(url, key);

    以dubbo源码中的Protocol 为例,对应dubbo源码中的rpc模块

    @SPI("dubbo")  public interface Protocol {            int getDefaultPort();        @Adaptive      <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;        @Adaptive      <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;      void destroy();   }

    java中的spi怎么用

    Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
    • Protocol接口,在运行的时候dubbo会判断一下应该选用这个Protocol接口的哪个实现类来实例化对象

    • 如果你配置了Protocol,则会将你配置的Protocol实现类加载到JVM中来,然后实例化对象时,就用你配置的那个Protocol实现类就可以了

    上面那行代码就是dubbo里面大量使用的,就是对很多组件,都是保留一个接口和多个实现,然后在系统运行的时候动态的根据配置去找到对应的实现类。如果你没有配置,那就走默认的实现类,即dubbo

    三、springboot 中SPI思想的使用

    我们知道,springboot框架相比spring,从配置文件上简化了不少,但简化的只是开发者看到的那些xml配置文件中的东西,其本质仍然未变,就算是少了xml配置文件,依旧在启动的时候,需要做配置的解析工作,如解析原来的数据库连接的xml配置文件中的内容加载到spring容器

    而springboot来说,很多看不到的配置文件,都是在容器启动过程中,自动将配置进行读取,解析和加载,而在这个过程中,我们不禁好奇,这些配置是存在哪里呢?这里就用到了SPI的思想,也就是涉及到springboot的自动装配过程

    举例来说,springboot怎么知道启动时需要加载 DataSource这个数据库连接的bean对象呢?怎么知道要使用JdbcTemplate 还是Druid的连接呢?

    在spingboot工程启动过程中,有很重要的一个工作,就是完成bean的自动装配过程,自动装配装配的是什么东西呢?简单来说就是:

    • 扫描classpath(工程目录下)下所有依赖的jar包装中指定目录中以特定的全限定名称的文件,进行解析并装配成bean

    • 扫描xml文件,解析xml配置并装配成bean

    • 解析那些被认为是需要装配的配置类,如@configuration,@service等

    其中第一步中的那些文件是什么呢?其实就是和dubbo或原生的spi规范中的那些 /META-INF 文件,只不过在springboot工程中,命名的格式和规范稍有不同

    下面通过源码来看看springboot启动过程中是如何加载这些spi文件的吧

    java中的spi怎么用

    然后来到下面这里,重点关注setInitializers 这个方法,顾名思义,表示在启动过程中要做的一些初始化设置,那么要设置哪些东西呢?

    java中的spi怎么用

    在这个方法中,有一个方法getSpringFactoriesInstances,紧接着这个方法看进去

    java中的spi怎么用

    在该方法中需要重点关注这句代码,通过这句代码,将依赖包下的那些待装配的文件进行加载,说白了,就是加载classpath下的那些 spring.factory的文件里面的name

    SpringFactoriesLoader.loadFactoryNames(type, classLoader)

    那么问题是具体加载的是什么样的文件呢?不妨继续点进去看看,在SpringFactoriesLoader类的开头,有一个这样的路径,想必大家就猜到是什么了吧

    java中的spi怎么用

    也就是说,会去找以这样的名字结尾的文件,比如我们在依赖的jar包中,看到下面这一幕,在这个spring.factories中,会看到更多我们熟悉的配置

    java中的spi怎么用

    java中的spi怎么用

    这样问题就很明白了,通过找到spring.factories的文件,然后解析出具体的类的完整的名称,然后再在:createSpringFactoriesInstances 这个方法中完成对这些 扩展的SPI接口实现类的初始化加载,即完成配的过程

    java中的spi怎么用

    感谢你能够认真阅读完这篇文章,希望小编分享的“java中的spi怎么用”这篇文章对大家有帮助,同时也希望大家多多支持编程网,关注编程网精选频道,更多相关知识等着你来学习!

    --结束END--

    本文标题: java中的spi怎么用

    本文链接: https://www.lsjlt.com/news/323227.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • java中的spi怎么用
      这篇文章主要介绍了java中的spi怎么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。前言在开发过程中,经常要用到第三方提供的SDK来完成一些业务扩展功能,比如调用第三方的...
      99+
      2023-06-29
    • java中SPI的作用是什么
      这篇文章将为大家详细讲解有关java中SPI的作用是什么,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。java基本数据类型有哪些Java的基本数据类型分为:1、整数类型,用来表示整数的数据类...
      99+
      2023-06-14
    • Java中怎么实现SPI机制
      Java中怎么实现SPI机制,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。2 什么是SPI机制SPI是Service Provider Interface 的简...
      99+
      2023-06-16
    • Java怎么用SPI实现解耦
      这篇“Java怎么用SPI实现解耦”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java怎么用SPI实现解耦”文章吧。概述S...
      99+
      2023-07-05
    • JAVA中的SPI是什么意思
      这篇文章主要介绍了JAVA中的SPI是什么意思,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1. SPI介绍SPI全称Service Provider Interface,是...
      99+
      2023-06-29
    • Java中的SPI机制是什么
      这篇文章主要介绍“Java中的SPI机制是什么”,在日常操作中,相信很多人在Java中的SPI机制是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中的SPI机制是什么”的疑惑有所帮助!接下来,请跟...
      99+
      2023-07-05
    • java SPI怎么定义接口
      这篇文章主要介绍了java SPI怎么定义接口的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇java SPI怎么定义接口文章都会有所收获,下面我们一起来看看吧。使用说明服务提供者提供接口的具体实现后,在jar包...
      99+
      2023-06-30
    • java中SPI的使用场景有哪些
      这期内容当中小编将会给大家带来有关java中SPI的使用场景有哪些,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Java的特点有哪些Java的特点有哪些1.Java语言作为静态面向对象编程语言的代表,实现...
      99+
      2023-06-14
    • JAVA中的SPI思想介绍
      目录1. SPI介绍2. SPI规则3. SPI案例3.1 组件的定义3.2 组件的实现3.3 组件的选用4. SPI原理5. SPI要求6. SPI应用总结1. SPI介绍 SPI...
      99+
      2024-04-02
    • Java中的SPI机制有哪些作用
      Java中的SPI机制有哪些作用?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Java的SPI机制实例详解SPI的全名为Service Provider Interface.普...
      99+
      2023-05-31
      java spi机制
    • 浅析Java中的SPI原理
      在面向对象的程序设计中,模块之间交互采用接口编程,通常情况下调用方不需要知道被调用方的内部实现细节,因为一旦涉及到了具体实现,如果需要换一种实现就需要修改代码,这违反了程序设计的&q...
      99+
      2024-04-02
    • java SPI的使用场景是什么
      本文小编为大家详细介绍“java SPI的使用场景是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“java SPI的使用场景是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。概念SPI是服务提供界面,JD...
      99+
      2023-06-30
    • 怎么进行Java SPI机制的分析
      这篇文章将为大家详细讲解有关怎么进行Java SPI机制的分析,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。为什么需要SPI?思考一个场景,我们封装了一套服务,别人通过引入我们写好...
      99+
      2023-06-22
    • Java的SPI机制是什么
      本篇内容介绍了“Java的SPI机制是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!SPI的全名为Service Provider In...
      99+
      2023-06-17
    • Java深入讲解SPI的使用
      目录什么是Java SPIJava SPI使用demoSPI在JDBC中的应用SPI在sharding-jdbc中的应用扩展什么是Java SPI   &ensp...
      99+
      2024-04-02
    • Java中的SPI机制案例分享
      目录1 简单介绍2 SPI 案例3 SPI 的原理剖析1 简单介绍 当我们封装了一套接口,其它项目想要调用我们的接口只需要引入我们写好的包,但是其它项目如果想要对我们的接口进行扩展,...
      99+
      2024-04-02
    • 如何理解Java中的SPI机制
      本篇内容介绍了“如何理解Java中的SPI机制”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!SPI的概念SPI在Java中的全称为Servi...
      99+
      2023-06-15
    • Java SPI用法案例详解
       1.什么是SPI      SPI全称Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的接...
      99+
      2024-04-02
    • 如何在java中使用SPI定义接口
      这篇文章给大家介绍如何在java中使用SPI定义接口,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Java有哪些集合类Java中的集合主要分为四类:1、List列表:有序的,可重复的;2、Queue队列:有序,可重复的...
      99+
      2023-06-14
    • 详解SPI在Dubbo中的应用
      目录一、概述二、JDK自带SPI2.1、代码示例2.2、简单分析三、SPI与双亲委派3.1、SPI加载到何处3.2、SPI是否破坏了双亲委派四、Dubbo SPI4.1、基本概念4....
      99+
      2024-04-02
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作