当前位置: 首页 > news >正文

Java中SPI机制原理解析

使用SPI机制前后的代码变化

  • 加载MySQL对JDBC的Driver接口实现
    在未使用SPI机制之前,使用JDBC操作数据库的时候,一般会写如下的代码:
    // 通过这行代码手动加载MySql对Driver接口的实现类
    Class.forName("com.mysql.jdbc.Driver")
    DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/study", "root", "root");
    
    在使用了SPI机制之后,就直接可以调用DriverManager.getConnection()方法获取连接了。
  • SLF4J查找日志门面实现
    在未使用SPI机制之前,SLF4J日志门面在查找具体的日志实现时,需要每个实现提供一个叫org.slf4j.com.impl.StaticLoggerBinder.class类,这里其实就跟SPI机制有点类似了,这个类实现了和SPI机制中的配置文件的功能,通过这个类来实现和具体实现的绑定关系。
    20240721170318
    使用了SPI机制之后则是通过SLF4JServiceProvider类来实现和具体实现的绑定关系。
    20240721171037
    20240721174312

SPI代码实现案例

假设现在有一个Plugin的接口,调用方通过PluginFactory中的installPlugins方法来加载实现实现类,并进行调用,代码如下所示:

// Plugin接口
public interface Plugin {boolean install(Map<Object, Object> context);
}public class PluginFactory {public void installPlugins() {Map<Object, Object> context = new HashMap<>();context.put("_beans", new ArrayList<>());context.put("_version", "1.0.0");context.put("_aspects", new HashMap<>());// 这里通过ServiceLoader加载Plugin的实现类ServiceLoader<Plugin> loader = ServiceLoader.load(Plugin.class);for (Plugin plugin : loader) {plugin.install(context);}}public static void main(String[] args) {PluginFactory factory = new PluginFactory();factory.installPlugins();}
}

Plugin接口实现者的代码:

public class LogPlugin implements Plugin {private static final Logger LOGGER = LogManager.getLogger();@Overridepublic boolean install(Map<Object, Object> context) {LOGGER.info("Login plugin is initiating...");return true;}
}

20240721214035
20240721214130

使用SPI机制有个好处就是:当需要切换不同的实现类时,无需对业务代码进行适配修改,直接将Maven配置里面的实现依赖切换即可,对于实际的环境可能就是直接将对应的jar包替换到对应的lib目录下,然后重启服务即可。

SPI代码实现原理

ServiceLoader的load方法实现原理是通过接口的全限定名称去读取META-INF/services路径下的文件,获取文件里面实现类的全限定名,然后加载该类,并通过反射的方式调用构造器获取实现类的实例,然后返回,如下图所示:
20240721215047

20240721214737

20240721215650

20240721214937

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • HarmonyOS应用开发者高级认证,Next版本发布后最新题库 - 多选题序号2
  • 第100+16步 ChatGPT学习:R实现Xgboost分类
  • 线段树分治+可撤销并查集 学习笔记
  • 机器学习数据集的一致性表现在哪些方面-九五小庞
  • buu做题(7)
  • 大数据开发之Hadoop
  • 【栈和队列】算法题 ---- 力扣
  • rsync文件远程同步
  • BiLSTM 实现股票多变量时间序列预测(PyTorch版)
  • 爬虫爬取网页的信息与图片的方法
  • SpringCloud03_loadbalancer的概述、负载均衡解析、切换、原理
  • Synchronized升级到重量级锁会发生什么?
  • 任务2:python+InternStudio 关卡
  • 第五节shell脚本中的运行流程控制(3)
  • 智能水果保鲜度检测:基于YOLO和深度学习的完整实现
  • 时间复杂度分析经典问题——最大子序列和
  • [译]Python中的类属性与实例属性的区别
  • 07.Android之多媒体问题
  • android百种动画侧滑库、步骤视图、TextView效果、社交、搜房、K线图等源码
  • JAVA_NIO系列——Channel和Buffer详解
  • PHP变量
  • UMLCHINA 首席专家潘加宇鼎力推荐
  • 从输入URL到页面加载发生了什么
  • 大快搜索数据爬虫技术实例安装教学篇
  • 基于web的全景—— Pannellum小试
  • 探索 JS 中的模块化
  • 项目实战-Api的解决方案
  • 消息队列系列二(IOT中消息队列的应用)
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • 从如何停掉 Promise 链说起
  • #565. 查找之大编号
  • $.ajax中的eval及dataType
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • %3cscript放入php,跟bWAPP学WEB安全(PHP代码)--XSS跨站脚本攻击
  • (1)(1.11) SiK Radio v2(一)
  • (代码示例)使用setTimeout来延迟加载JS脚本文件
  • (规划)24届春招和25届暑假实习路线准备规划
  • (十二)springboot实战——SSE服务推送事件案例实现
  • .bashrc在哪里,alias妙用
  • .net6Api后台+uniapp导出Excel
  • .net网站发布-允许更新此预编译站点
  • .Net中ListT 泛型转成DataTable、DataSet
  • /proc/interrupts 和 /proc/stat 查看中断的情况
  • @Documented注解的作用
  • [100天算法】-不同路径 III(day 73)
  • [AMQP Connection 127.0.0.1:5672] An unexpected connection driver error occured
  • [android学习笔记]学习jni编程
  • [APIO2015]巴厘岛的雕塑
  • [C/C++]数据结构 循环队列
  • [CISCN2019 华东北赛区]Web2
  • [emacs] CUA的矩形块操作很给力啊
  • [Google Guava] 1.1-使用和避免null
  • [IE9] IE9 beta版下载链接
  • [JDK工具-6] jmap java内存映射工具
  • [leetcode] 四数之和 M