三种SPI机制的了解及使用

news2024/11/24 17:49:59

文章目录

      • 1.SPI机制概念
      • 2.Java SPI
        • 2.1 创建一个项目,并创建如下模块
        • 2.2 db-api模块
        • 2.3 mysql-impl模块
        • 2.4 oracle-impl模块
        • 2.5 main-project模块
      • 3.Spring SPI
      • 4.Dubbo SPI

1.SPI机制概念

SPI全程Service Provider Interface,是一种服务发现机制。
SPI的本质就是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类型。这样就可以运行时,动态为接口替换实现类。

正因此特性,我们可以很容易的通过SPI机制为我们的程序提供拓展功能。
在这里插入图片描述

2.Java SPI

2.1 创建一个项目,并创建如下模块

注意模块之间需要对应引用依赖,比如:db-api需要被其他三个模块引入,main-project要引入两个实现模块依赖。
在这里插入图片描述

2.2 db-api模块

在这里插入图片描述

public interface DBApi {
    void getDBImpl();
}
2.3 mysql-impl模块

在这里插入图片描述
实现DBApi接口,并且在resources下创建META-INF/services/全限定接口名称文件,这里如上图所示,然后文件中写实现类的全限定类名。

com.linging.impl.MysqlImpl
2.4 oracle-impl模块

在这里插入图片描述
同上,文件中写oracle的实现类全限定类名:

com.linging.impl.OracleImpl
2.5 main-project模块

在这里插入图片描述
引入依赖:

 <dependencies>
        <dependency>
            <groupId>com.linging</groupId>
            <artifactId>db-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.linging</groupId>
            <artifactId>mysql-impl</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.linging</groupId>
            <artifactId>oracle-impl</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
public class Application {

    public static void main(String[] args) {
        ServiceLoader<DBApi> serviceLoader = ServiceLoader.load(DBApi.class);
        Iterator<DBApi> it = serviceLoader.iterator();
        while(it.hasNext()){
            DBApi next = it.next();
            // 判断具体实现类,进行处理...
            if(next.getClass().equals(MysqlImpl.class)){
                System.out.println("找到特定实现类");
            }
            next.getDBImpl();
        }
    }
}

通过上面的解析,可以发现,使用JavaSPI机制存在一些缺陷:

  • 不能按需加载,需要遍历所有实现,并实例化,然后在循环中才能找到我们需要的实现类,当某个实现类实例化很耗时,它也被载入并实例化,这就造成加载耗时过长。
  • 多个并发多线程使用ServiceLoader类的实例不安全。

3.Spring SPI

Spring SPI沿用了Java SPI的设计思想,采用spring.factories方式实现SPI机制,可以在不修改源码的前提下,提供Spring框架的扩展性。
在这里插入图片描述
引入spring依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

db-api模块:

public interface DBApi {
    void getDBImpl();
}

xxx-impl实现模块的不同:
在这里插入图片描述
spring,factories中的内容:

com.linging.api.DBApi=com.linging.impl.MysqlImpl

main-project模块:

public class Application {

    public static void main(String[] args) {
        List<DBApi> loadFactories =
                SpringFactoriesLoader.loadFactories(DBApi.class, Thread.currentThread().getContextClassLoader());
        Iterator<DBApi> it = loadFactories.iterator();
        while(it.hasNext()){
            DBApi next = it.next();
            next.getDBImpl();
        }
    }
}

Spring SPI机制和JavaSPI机制很类似,但是还有一些差异:

  • JavaSPI机制是一个服务提供接口对应一个配置文件,配置文件中存放当前接口的所有实现类,所有配置文件放在META-INF/services目录下。
  • SpringSPI是仅有一个META-INF/spring.factories配置文件存放多个接口及对应的实现类,以接口限定类名作为key,实现类作为value,多个实现类用逗号隔开。
  • 和JavaSPI一样,SpringSPI也无法获取某个固定的实现,只能按顺序遍历获取所有实现,从中获取自己想要的实现。

4.Dubbo SPI

在这里插入图片描述
引入dubbo依赖:

<dependency>
     <groupId>org.apache.dubbo</groupId>
     <artifactId>dubbo</artifactId>
     <version>2.7.12</version>
 </dependency>

db-api模块:

@SPI
public interface DBApi {
    void getDBImpl();
}

xxx-impl模块:
在这里插入图片描述
配置文件内容:

mysql=com.linging.impl.MysqlImpl

main-project模块:

public class Application {
    public static void main(String[] args) {
        ExtensionLoader<DBApi> extensionLoader = ExtensionLoader.getExtensionLoader(DBApi.class);
        // 按需加载
        DBApi mysql = extensionLoader.getExtension("mysql");
        mysql.getDBImpl();
    }
}
  • 基于JavaSPI的缺陷无法支持接口按需加载接口实现类,Dubbo并未使用JavaSPI,而是重新实现了一套功能更强的SPI机制。
  • Dubbo SPI的相关逻辑被封装在ExtensionLoader类中,通过它可以加载指定的实现类。
  • Dubbo SPI所需的配置文件放在META-INF/dubbo路径下,配置内容如下:文件名为接口全限定类名,内容为key=value的键值对,key为实现类的标识别名,value为实现类的全限定类名,这样就可以实现按需加载了。
  • 在使用时,需要在接口上加@SPI注解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2229681.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux系统编程】第四十弹---深入理解操作系统:信号捕捉、可重入函数、volatile关键字与SIGCHLD信号解析

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、捕捉信号 1.1、内核如何实现信号的捕捉 1.2、内核态与用户态 1.3.1、用户态&#xff08;User Space&#xff09; 1.3.2、…

【面试】数组中 Array.forEach()、Array.map() 遍历结束后是否改变原数组

forEach 、map 同理 数组内元素是 基本数据类型 时&#xff0c; 1.1. 直接给 item赋值&#xff0c;是 不会改变原数组 的&#xff08;如图中1&#xff09;&#xff0c; 1.2. 通过 原数组索引赋值 是会改变原数组的&#xff08;如图中2&#xff09;数组内元素是 复杂数据类型 时…

List<T>属性和方法使用

//author&#xff1a;shark_ddd using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;//使用函数来减少长度namespace List_T {class Student{public string Name { get; set; }public int Age { get; set; …

liunx CentOs7安装MQTT服务器(mosquitto)

查找 mosquitto 软件包 yum list all | grep mosquitto出现以上两个即可进行安装&#xff0c;如果没有出现则需要安装EPEL软件库。 yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm查看 mosquitto 信息 yum info mosquitto安装 mosquitt…

视频去水印软件哪个好?这些软件值得一试

无论是社交媒体上的短视频&#xff0c;还是专业网站上的长视频&#xff0c;去除视频中的水印成为了许多人的需求。 选择一款合适的视频去水印软件&#xff0c;可以帮助我们轻松去除视频中的不必要标记&#xff0c;保持视频的完整性和美观。 那么&#xff0c;视频去水印软件哪…

qt QDoubleSpinBox详解

1、概述 QDoubleSpinBox是Qt框架中的一个控件&#xff0c;专门用于浮点数&#xff08;即小数&#xff09;的输入和调节。它提供了一个用户界面元素&#xff0c;允许用户在预设的范围内通过拖动滑块、点击箭头或使用键盘来递增或递减浮点数值。QDoubleSpinBox通常用于需要精确数…

在基于AWS EC2的云端k8s环境中 搭建开发基础设施

中间件下载使用helm,这里部署的都是单机版的 aws-ebs-storageclass.yaml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata:name: aws-ebs-storageclass provisioner: kubernetes.io/aws-ebs parameters:type: gp2 # 选择合适的 EBS 类型&#xff0c;如 gp2、io1…

MATLAB与STK互联:仿真并获取低轨卫星与指定区域地面站的可见性数据

MATLAB控制STK实现&#xff1a;仿真并获取低轨卫星与指定区域地面站的可见性数据 本次仿真主要参考了多篇文献和网站&#xff0c;包括但不限于&#xff1a;《Using MATLAB for STK Automation》、CSDN博文&#xff1a; 拜火先知的博客_CSDN博客-笔记、AGI官网有关MATLAB的内容…

docker engine stopped

1&#xff09;环境&#xff1a;win 10 2&#xff09;docker安装时已经已经安装了虚拟机 3&#xff09;启用网络适配器 4&#xff09;启用docker服务&#xff08;依赖服务LanmanServer&#xff09; 5&#xff09;全都弄好了&#xff0c;docker还是打不开&#xff0c;没办法了&a…

天翼网关 3.0 兆能 ZNHG600 获取超级密码改桥接

本文首发于只抄博客&#xff0c;欢迎点击原文链接了解更多内容。 前言 前不久朋友家断网&#xff0c;喊了宽带师傅修完之后&#xff0c;光猫就从桥接模式变成了路由模式。虽然对于日常上网来说区别不大&#xff0c;但这条宽带有公网 IP&#xff0c;通过光猫拨号的话&#xff0…

C语言常见进制 (二进制、八进制、十进制、十六进制)详解

C语言常见进制的详解 放在最前面的前言&#xff1a;1、分类2、二进制&#xff08;2.1&#xff09;二进制的解释说明&#xff08;2.2&#xff09;关于二进制的计算&#xff08;2.3&#xff09; 二进制转换为八进制&#xff08;2.4&#xff09; 二进制转换为十进制 3、八进制&…

在 .NET 8 Web API 中实现 Entity Framework 的 Code First 方法

本次介绍分为3篇文章&#xff1a; 1&#xff1a;.Net 8 Web API CRUD 操作.Net 8 Web API CRUD 操作-CSDN博客 2&#xff1a;在 .Net 8 API 中实现 Entity Framework 的 Code First 方法https://blog.csdn.net/hefeng_aspnet/article/details/143229912 3&#xff1a;.NET …

初识动态规划(由浅入深)

&#x1f913; 动态规划入门与进阶指南 &#x1f4d8; 动态规划&#xff08;Dynamic Programming, DP&#xff09;是一种非常经典的&#x1f4d0;算法方法&#xff0c;特别适合用来解决那些有大量重复计算的问题&#x1f300;。它可以将复杂的问题拆分为小问题&#x1f9e9;&a…

【STM32】SD卡

(一)常用卡的认识 在学习这个内容之前&#xff0c;作为生活小白的我对于SD卡、TF卡、SIM卡毫无了解&#xff0c;晕头转向。 SD卡&#xff1a;Secure Digital Card的英文缩写&#xff0c;直译就是“安全数字卡”。一般用于大一些的电子设备比如&#xff1a;电脑、数码相机、AV…

《JVM第5课》虚拟机栈

无痛快速学习入门JVM&#xff0c;欢迎订阅本免费专栏 Java虚拟机栈&#xff08;Java Virtual Machine Stack&#xff0c;简称JVM栈&#xff0c;又称Java方法栈&#xff09;是 JVM 运行时数据区的一部分&#xff0c;主要用于支持Java方法的执行。每当一个新线程被创建时&#xf…

Java Executor RunnableScheduledFuture 总结

前言 相关系列 《Java & Executor & 目录》《Java & Executor & RunnableScheduledFuture & 源码》《Java & Executor & RunnableScheduledFuture & 总结》《Java & Executor & RunnableScheduledFuture & 问题》 涉及内容 《…

软考(中级-软件设计师)数据库篇(1101)

第6章 数据库系统基础知识 一、基本概念 1、数据库 数据库&#xff08;Database &#xff0c;DB&#xff09;是指长期存储在计算机内的、有组织的、可共享的数据集合。数据库中的数据按一定的数据模型组织、描述和存储&#xff0c;具有较小的冗余度、较高的数据独立性和扩展…

zynq PS端跑Linux响应中断

这篇文章主要是讲述如何在Zynq的PS上跑Linux启动IRQ&#xff0c;环境为vivado2019.1&#xff0c;petalinux2019.1 ubuntu20.04&#xff0c;本人初学者&#xff0c;欢迎批评指正 1. Vivado硬件设计 确保自定义IP的中断信号通过 IRQ_F2P 连接到PS端。在开始Petalinux配置之前&a…

R语言贝叶斯

原文链接&#xff1a;R语言贝叶斯进阶&#xff1a;INLA下的贝叶斯回归、生存分析、随机游走、广义可加模型、极端数据的贝叶斯分析https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247625527&idx8&snba4e50376befd94022519152609ee8d0&chksmfa8daad0cdfa…

qt QRadioButton详解

QRadioButton 是一个可以切换选中&#xff08;checked&#xff09;或未选中&#xff08;unchecked&#xff09;状态的选项按钮。单选按钮通常呈现给用户一个“多选一”的选择&#xff0c;即在一组单选按钮中&#xff0c;一次只能选中一个按钮。 重要方法 QRadioButton(QWidget…