SPI机制详解

SPI机制详解

什么是SPI机制?

SPI:Service Provider Interface,中文直译:服务提供者接口,它通过在ClassPath路径下的META-INF/service文件夹中查找文件,并自动加载文件里所定义的类
在这里插入图片描述

在面向对象的设计原则中,一般推荐模块之间基于接口编程,通常情况下调用方模块是不会感知到被调用方模块的内部具体实现。一旦代码里面涉及具体实现类,就违反了开闭原则。如果需要替换一种实现,就需要修改代码。

为了实现在模块装配的时候不用在程序里面动态指明,这就需要一种服务发现机制。Java SPI 就是提供了这样一个机制:为某个接口寻找服务实现的机制。这有点类似 IoC 的思想,将装配的控制权移交到了程序之外。

SPI机制的出现是为了解决什么问题?

举个经典的栗子,在后端开发中,不可避免的就是通过JDBC去连接数据库,但是不同的数据库有不同的驱动,MySQL有MySQL的驱动,Oracle有Oracle的驱动,但是它们都实现了JDBC接口

在这里插入图片描述

假如现在有个需求,项目原来使用的是MySQL作为数据库,但是现在要替换成Oracle数据库,怎么实现?

去项目中手动去改变Driver的实现类?

Driver driver = new OracleDriverImpl();

太不优雅了,太不体面了🤣

有没有一种方法能动态替换实现类,如果我现在导入的Jar包是MySQL的驱动我就将Driver的实现类定义为MySQL的驱动包,导入的Jar包是Oracle的驱动我就将Driver的实现类定义为Oracle的驱动包?

诶,Java开发者定义了这样一个规则,在项目的ClassPath目录中创建META-INF/Services目录,在这里面创建以接口名为文件名,内容为实现类的全限定名的一个文件;

在这里插入图片描述

再通过IO的方式获取到所有的全限定名,如果存在MySQL数据库的驱动,那么calssNameList = [“com.mysql.cj.jdbc.Driver”]

以下代码为伪代码,在java.util.ServiceLoader#load(Class clazz) 完成了spi 的实现,具体的思想跟下面的流程类似,感兴趣的可以去看一看

在这里插入图片描述

SPI这种方式可以很好解决不同框架之间的拓展问题,可以同时兼容同一个接口的多个实现类;

SPI机制的变种

学过SpringBoot的童鞋们都知道自动装配绝对是SpringBoot的大招,它可以将外部框架的配置类动态的加载到我们IOC的容器中;其实它的思想与SPI机制非常类似;

以mybatis-plus为例

在这里插入图片描述

问题:因为mybatis-plus的ClassPath与我们的项目路径不同,肯定是不能通过扫描注解的方式注入到IOC中

那么SpringBoot定义了一个机制,如果这些框架想将自己的配置类注入到使用者的IOC中,你可以在框架包的ClassPath下创建一个META-INF目录,在这个目录中创建一个spring.factories文件

在这里插入图片描述

在这里插入图片描述

在SpringBoot项目启动时,会加载所有Jar包下META-INF/spring.factories文件,根据org.springframework.boot.autoconfigure.EnableAutoConfiguration后面的全限定类名,通过反射将这个类加载到IOC的容器中

这样就达到了项目与框架之间的解耦,在项目不需要手动去将这些框架的配置类加载到IOC容器中;

除了SpringBoot的自动装配体现了SPI的思想,还有例如Dubbo、Slf4j等等

总结
  1. SPI机制能够使接口与具体的实现类解耦,可以根据实际的业务情况启用或替换具体组件
  2. SPI机制为很多框架的拓展提供了可能
  3. SPI机制更多的是一种思想

如果觉得本篇文章对于您有帮助,可否点个小赞😺;篇幅较长建议收藏🫠;关注一手等待后续更新更多干货🚀

参考视频:https://www.bilibili.com/video/BV1E44y1N7Nk/?spm_id_from=333.337.search-card.all.click&vd_source=835177d483a47b8fcf9934ddad59626a

参考文章:https://javaguide.cn/java/basis/spi.html

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

踩坑(乱改配置,电脑都打不开,无奈暴力重装)文末有惊喜喔

总结我的论文项目的傻逼开端。(想的很好,思路也对,也做了,但是过程和结果好像并不是想象中那么容易) 故事讲解: 本来我只有一台电脑,这个电脑上面东西比较杂。学习资料呀,笔记呀&a…

【使用postman测试python接口】

打开python服务 设置postman如下,并发送: postman新建请求设置请求方式为post设置地址、raw、json方式、内容如下 结果: python如下: from flask import Flask, request, jsonifyapp Flask(__name__) # 实例化对象app.route…

JVM理解学习

参考视频 运行时数据区 JVM架构总览图 绿色的:方法区,堆,是所有线程共享的 黄色的: 虚拟机栈,本地方法栈,程序计数器,是线程私有的 程序计数器 程序计数器是一块较小的内存空间,物…

macbook安装brew出现错误解决办法

我是使用国内的源安装brew的时候: /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 我选择了 1: 就出错了,后来切换为2重新安装就好了 安装完成后提示获取不到系统版本: Failed to co…

Linux使用Docker部署Registry结合内网穿透实现公网远程拉取推送镜像

文章目录 1. 部署Docker Registry2. 本地测试推送镜像3. Linux 安装cpolar4. 配置Docker Registry公网访问地址5. 公网远程推送Docker Registry6. 固定Docker Registry公网地址 Docker Registry 本地镜像仓库,简单几步结合cpolar内网穿透工具实现远程pull or push (拉取和推送)…

Linux服务器(Debian系)包含UOS安全相关巡检shell脚本

#!/bin/bash# Define output file current_date$(date "%Y%m%d") # Gets the current date in YYYYMMDD format output_file"server_security_inspection_report_${current_date}.txt"# Empty the file initially echo > $output_file# 获取巡检时间 (…

Hadoop学习1:概述、单体搭建、伪分布式搭建

文章目录 概述基础知识Hadoop组件构成Hadoop配置文件 环境准备配置Hadoop配置下载配置环境变量 Hadoop运行模式Standalone Operation(本地)官方DemoWordCount单词统计Demo Pseudo-Distributed Operation(伪分布式模式)配置修改启动…

NCV4275CDT50RKG稳压器芯片中文资料规格书PDF数据手册引脚图图片价格功能

产品概述: NCV4275C 是一款低漏稳压器,可用于严酷汽车环境。它包括了较宽的运行温度范围和输出电压范围。输出调节为 5.0 V 或 3.3 V,额定输出电流为 450 mA。它还提供过电流保护、超温保护和可编程微处理器重置等多种功能。NCV4275C 采用 D…

Python Learn day05

Python Learn day05 本文主要讲解 继承、多态、定制类 继承和多态 什么是继承 当新类想要拥有现有类的功能结构,可以使用继承。继承的前提是新类 is a 现有类,即: 子类 is 父类 总是从某个类继承: class Myclass(object):pass…

Vue+OpenLayers7入门到实战:OpenLayers如何使用全屏控件,来实现地图容器的全屏和退出全屏功能

返回《Vue+OpenLayers7》专栏目录:Vue+OpenLayers7入门到实战 前言 本章介绍如何使用OpenLayers7在地图上使用地图全屏控件,来控制地图容器的全屏和退出全屏的功能。 注意:这里的全屏控件全屏指的是地图容器全屏,并非整个网页全屏。 网页整体全屏和指定网页节点全屏可以参…

十五、计算机视觉-sobel算子

文章目录 前言一、sobel算子的概念二、sobel算子的计算方式三、具体实现 前言 上节课我们学习了梯度的知识,学习了如何去计算梯度,本节我们继续学习计算梯度的方法,本节我们学习使用Sobel算子计算梯度,这与上节课梯度计算方法有所…

ARMv8架构特殊寄存器介绍-0

一、zero 寄存器 零寄存器用作源寄存器时读取零,用作目标寄存器时丢弃结果。您可以在大多数指令中使用零寄存器,但不是所有指令。二、sp寄存器 在ARMv8架构中,要使用的堆栈指针的选择在某种程度上与Exception级别。默认情况下,异…

大数据Doris(六十九):项目线上表现

文章目录 项目线上表现 一、查询响应时间

java学习之路-程序逻辑控制

目录 1.分支结构 1.1 if语句 栗子 判断奇数还是偶数 判断一个年份是否为闰年 1.2switch语句 栗子 2. 循环结构 2.1while 循环 栗子 2.2break和continue break continue 2.3for循环 基本语法 栗子 2.4 do while 循环 3.输入输出 3.1输出 3.2从键盘输入 栗子…

基于FPGA的光纤通信系统的实现的优化技巧与方法

逻辑电路基本框架回顾 跨时钟域同步技术 读写操作相互独立时钟域 A 和 B 不需要一致的相位由专门逻辑控制读写操作的切换 高速数据的乒乓缓存技术

SimpleDateFormat类 --java学习笔记

SimpleDateFormat 代表简单日期格式化,可以用来把日期对象、时间毫秒值格式化成我们想要的形式 常见构造器和方法: pattern 代表需要应用的时间格式—— 时间格式的常见符号: 时间格式的应用举例: import java.text.SimpleDate…

集合系列(二) -List接口详解

一、List简介 List 的数据结构就是一个序列,存储内容时直接在内存中开辟一块连续的空间,然后将空间地址与索引对应。 以下是List集合简易架构图 由图中的继承关系,可以知道,ArrayList、LinkedList、Vector、Stack都是List的四个…

【计算机网络】UDP/TCP 协议

TCP 协议 一、传输层1. 再谈端口号2. 端口号范围划分3. 进程和端口号4. netstat5. pidof 二、UDP 协议1. UDP 协议端格式(报文)2. UDP 的特点3. 面向数据报4. UDP 的缓冲区 三、TCP 协议1. 认识 TCP2. TCP 协议段格式(1)4 位首部长度(2&#…

Android U pipeline-statusbar

Android U - statusbar pipeline 写在前面 Android原生从T开始对SystemUI进行MVVM改造,U上状态栏部分进行了修改;第一次出现修改不会删除原有逻辑,而是两版并行,留给其他开发者适配的时间;在下一个大版本可能会删除原…

Java获取视频封面图,利用FFmpegFrameGrabber获取视频封面图

依赖 <dependency><groupId>org.bytedeco</groupId><artifactId>javacv-platform</artifactId><version>1.5.9</version></dependency>传入视频流获取图片byte /*** 获取视频截图** param frameNumber 视频的指定帧数* param …