Java基础---SPI

news2024/11/16 19:50:00

目录

典型回答

从面向接口编程说起

接口位于调用方所在的包中

接口位于实现方所在的包中

注意

如何定义一个SPI

SPI的实现原理

SPI的应用场景


  • 典型回答

  • Java中区分 API 和 SPI,通俗的讲:API 和 SPI 都是相对的概念,他们的差别只在语义上,API 直接被应用开发人员使用,SPI 被框架扩展人员使用
  • API Application Programming Interface
    • 大多数情况下,都是实现方来制定接口并完成对接口的不同实现,调用方仅仅依赖却无权选择不同实现
  • SPI Service Provider Interface
    • 而如果是调用方来制定接口,实现方来针对接口来实现不同的实现;调用方来选择自己需要的实现方
  • 从面向接口编程说起

  • 接口调用

  • 当选择在调用方和实现方中间引入 接口
  • 上图没有给出“接口”应该位于哪个“包”中,从纯粹的可能性上考虑,有三种选择:
    • 1-接口位于实现方所在的包中
    • 2-接口位于调用方所在的包中
    • 3-接口位于独立的包中
  • 接口位于调用方所在的包中

  • 对于类似这种情况下接口,将其称为SPI
  • SPI的规则如下:
    • 概念上更依赖调用方
    • 组织上位于调用方所在的包中
    • 实现位于独立的包中
  • 常见的例子是:插件模式的插件;如:
    • 数据库驱动 Driver
    • 日志 Log
    • dubbo扩展点开发
  • 接口位于实现方所在的包中

  • 对于类似这种情况下的接口,将其称作为API
  • API的规则如下:
    • 概念上更接近实现方
    • 组织上位于实现方所在的包中
  • 注意

  • SPI 和 API 也不一定是接口,这里都是指狭义的具体的接口

  • API是你可以引用来达成某个目标的对象,它清楚地告诉你它可以完成什么目标,用户可以即插即用
  • 而SPI则指定了你要达成某个目标你必须要继承或实现它,它一般只供某些特殊用途的接口开发商使用(当然有些公司或个人也可以自己继承或实现SPI来完成特定功能)
  • 如何定义一个SPI

  • 步骤1
    • 定义一组接口 (假设是org.foo.demo.IShout),并写出接口的一个或多个实现,(假设是org.foo.demo.animal.Dog、org.foo.demo.animal.Cat)

  • 步骤2
    • 在src/main/resources/ 下建立 /META-INF/services 目录,新增一个以接口命名的文件 (org.foo.demo.IShout文件),内容是要应用的实现类(这里是org.foo.demo.animal.Dog和org.foo.demo.animal.Cat,每行一个类)
    • org.foo.demo.animal.Dog
    • org.foo.demo.animal.Cat
  • 步骤3
    • 使用 ServiceLoader 来加载配置文件中指定的实现

    • 代码输出:

  • SPI的实现原理

  • 看ServiceLoader类的签名类的成员变量:

  • 参考具体源码,梳理一下,实现的流程如下:
  • 1-应用程序调用ServiceLoader.load方法,ServiceLoader.load方法内先创建一个新的ServiceLoader,并实例化该类中的成员变量,包括:
    • a. loader(ClassLoader类型,类加载器)
    • b. acc(AccessControlContext类型,访问控制器)
    • c. providers(LinkedHashMap类型,用于缓存加载成功的类)
    • d. lookupIterator(实现迭代器功能)
  • 2-应用程序通过迭代器接口获取对象实例
    • a. ServiceLoader先判断成员变量providers对象中(LinkedHashMap类型)是否有缓存实例对象,如果有缓存,直接返回
    • b. 如果没有缓存,执行类的装载:
      • ⅰ. 读取META-INF/services/下的配置文件,获得所有能被实例化的类的名称
      • ⅱ. 通过反射方法Class.forName()加载类对象,并用instance()方法将类实例化
      • ⅲ. 把实例化后的类缓存到providers对象中(LinkedHashMap类型)
      • ⅳ. 然后返回实例对象
  • SPI的应用场景

  • 概括地说,适用于:调用者根据实际使用需要,启用、扩展、或者替换框架的实现策略
  • 比较常见的例子:
    • 1-数据库驱动加载接口实现类的加载
    • 2-JDBC加载不同类型数据库的驱动
    • 3-日志门面接口实现类加载
    • 4-SLF4J加载不同提供商的日志实现类
  • Spring
  • Spring中大量使用了SPI
  • 比如:对servlet3.0规范对ServletContainerInitializer的实现、自动类型转换Type Conversion SPI(Converter SPI、Formatter SPI)等
  • Dubbo
  • Dubbo中也大量使用SPI的方式实现框架的扩展,不过它对Java提供的原生SPI做了封装,允许用户扩展实现Filter接口

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

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

相关文章

从零开始的Android逆向工程,开启对应用程序内部的探索之旅

Android逆向有那些发展方向 安全评估: 逆向工程可以帮助安全专家分析和评估Android应用程序的安全性。通过逆向应用程序,发现潜在的漏洞和安全隐患,并提供改进建议,以加强应用程序的安全性。 应用改进和优化: 逆向…

java编码转换过程

常见的JAVA程序包括以下类别: *直接在console上运行的类(包括可视化界面的类) *JSP代码类(注:JSP是Servlets类的变型) *Servelets类 *EJB类 *其它不可以直接运行的支持类 这些类文件中,都有可能含有中文字符串&…

KDE缺少全屏启动器的解决办法

我记得以前KDE是有一个全局搜索的启动起来着,但是重装了一次之后发现只剩下一个半屏的了。解决方案如下 sudo apt-get install plasma-widgets-addons

三菱PLC 红绿灯 步进指令 STL

自己写的红绿灯。 有启动、停止两个按钮。 南北通行4S,东西通行5S。 链接: https://caiyun.139.com/m/i?0E5CJEoVGt4D0 提取码:kVOA SET(启动,启动标志); RST(启动,停止标志); SET(停止,停止标志); RST(停止,启动标志); RST(LDP(TRUE,停止),T0); RST(LDP(TRUE…

范德波尔方程可视化

Van der Pol方程如下所示 d x d t y d y d t − x ( 1 − x 2 ) y \begin{equation} \begin{aligned} \frac{dx}{dt} & y \\ \frac{dy}{dt} & -x(1-x^2)y \end{aligned} \end{equation} dtdx​dtdy​​y−x(1−x2)y​​​ 相应的程序如下 为了观看长期趋势&…

VUE项目打包成apk

在我们的开发需求中,可能会遇到需要将vue项目中的H5代码打包成一个安卓的app,那么我为大家介绍一套保姆级的解决方案,看完你就会。 VUE HBuilder 1.准备工作: 需要下载一个HBuilder X编辑器,不过我相信大家身为前端…

最适合新手的SpringBoot+SSM项目《苍穹外卖》实战—(四)集成 Swagger

文章目录 Swagger 介绍集成 Swagger常用注解 黑马程序员最新Java项目实战《苍穹外卖》,最适合新手的SpringBootSSM的企业级Java项目实战。 Swagger 介绍 Swagger 是一个开源的 API 设计工具,它可以用于描述、设计、开发和测试 RESTful API。 它提供了一…

【C++11】 线程库的使用

文章目录 1 线程库的基本使用1.1 thread1.2 this_thread1.3 线程函数参数 2 mutex2.1 mutex的基本使用2.2 mutex系列锁2.3 lock_guard与unique_lock 3 原子操作4 条件变量 1 线程库的基本使用 1.1 thread 在C11之前,涉及到多线程问题,都是和平台相关的&…

研究一下「pnpm」这个神奇的包管理工具

最近搬砖 🧱 在搞前端项目部署优化 🎡,大部分项目的包管理工具都已经从 npm/yarn 替换成了 pnpm,整体来看无论是在 install 或是 build 阶段都提速了不少 🚀,借此时机,做个总结!&…

TypeScript 中【类型断言】得使用方法

类型断言的概念 有些时候开发者比TS本身更清楚当前的类型是什么&#xff0c;可以使用断言&#xff08;as&#xff09;让类型更加精确和具体。 类型断言&#xff08;Type Assertion&#xff09;表示可以用来手动指定一个值的类型。 类型断言语法&#xff1a; 值 as 类型 或 <…

vue3 实现多层级列表

文章目录 需求背景解决效果index.vue视频效果 需求背景 需要在统一个列表下&#xff0c;实现商品和规格得管理和联动 解决效果 index.vue <!--/*** author: liuk* date: 2023/7/7* describe: 商品列表 */--> <template><div class"container">&…

textarea自适应高度二——(设置隐藏div获取高度和仿element-ui组件)

文章目录 前言一、通过隐藏div的方式来设置文本域自适应高度1. 新增一个文本域样式一个的dom&#xff0c;但是里面的textarea改为div2. 隐藏div的class3.设置文本域高度的方法 二、仿element-ui组件设置textarea自适应高度1.element-ui中自适应效果2. 看源码&#xff0c;盘逻辑…

病毒专题丨 plugx病毒

一、病毒简述 之前分析了一下&#xff0c;分析的较为简单&#xff0c;这次又详细分析了一下。 文件名称 00fbfaf36114d3ff9e2c43885341f1c02fade82b49d1cf451bc756d992c84b06 文件格式 RAR 文件类型(Magic) RAR archive data, v5 文件大小 157.74KB SHA256 00fbfaf36114d3ff9e…

【编程中的数学】:冰雹猜想

今天和大家分享一个令人着迷的数学谜题——冰雹猜想。这个谜题曾在1976年引起轰动&#xff0c;当时《华盛顿邮报》以头版头条刊登了一篇关于它的报道。让我们一起探索这个数学游戏的奥秘。 70年代中期&#xff0c;美国一所名牌大学的校园内兴起了一种数学游戏&#xff0c;这个游…

微信小程序使用vant时间选择器二次封装成自定义区间时间选择

目录 1.引入vant组件库 2.wxml页面 3.js页面 1.引入vant组件库 1.安装vant # 通过 npm 安装 npm i vant/weapp -S --production # 通过 yarn 安装 yarn add vant/weapp --production # 安装 0.x 版本 npm i vant-weapp -S --production 2.将 app.json 中的 "style&quo…

2-需求

目录 1.需求的定义 1.1.用户需求 1.2.软件需求 PS&#xff1a;软件需求规格说明书 2.为什么有需求&#xff1f; PS&#xff1a;为什么需求对软件测试人员如此重要&#xff1f; 3.测试人员眼里的需求 4.如何深入了解需求&#xff1f; 4.1.参加需求评审会议 4.2.查阅文…

数据结构初阶--二叉树OJ1

目录 二叉树的最大深度思路分析代码实现 相同的树思路分析代码实现 单值二叉树思路分析代码实现 二叉树的前序遍历思路分析代码实现 翻转二叉树思路分析代码实现 对称二叉树思路分析代码实现 另一棵树的子树思路分析代码实现 二叉树的最大深度 先来看题目描述 思路分析 题目…

QT学习—串口LED小项目

前言——博主刚开始接触QT&#xff0c;本文参考博主嵌入式大杂烩的一篇博文易懂 | 手把手教你编写你的第一个上位机&#xff0c;初步学习一下QT开发。 文章目录 一、QT安装二、新建工程三、创建上位机界面3.1 修改控件名3.2 添加槽函数 四、上位机程序打包五、上位机测试六、总…

不要用 in + 子查询

前两天我的 VIP 用户向我抛出了一个 SQL 问题&#xff0c;他的 MySQL 是 8.x版本&#xff1a; 大概意思如下 sql &#xff1a; select * from A where id in (select max(id) as id from A where task_id in(1,2,3) group by task_id );这个 A 表中是有 task_id 这个索引的。 …

【转换】编码转换工具笔记

应用场景 应用场景是程序整合第三方库多平台运行&#xff0c;第三方库window平台编译&#xff0c;代码移植到linux出现bom问题 思考解决 windows使用utf-8编码&#xff0c;linux使用utf-8无bom编码 工具主要针对utf-8编码文件&#xff0c;能够批量添加删除BOM&#xff0c;无…