Java SPI(Service Provider Interface)

Java SPI是Java标准库提供的一种服务发现机制,它通过在classpath下约定的META-INF/services目录中,定义接口和其实现类之间的对应关系,从而动态加载目标接口的实现类。

通过一个实际例子来具体看一下
1、定义接口

public interface Animal {void sayHello();
}

2、实现类
这里搞两个实现类

public class Cat implements Animal {@Overridepublic void sayHello() {System.out.println("喵喵");}
}
public class Dog  implements Animal{@Overridepublic void sayHello() {System.out.println("汪汪");}
}

3、添加配置文件
在resources目录下创建文件夹META-INF/services。
然后在该目录下创建一个文件,以接口的全包名为文件名
如我们这里的Animal接口就要创建
com.test.Animal文件,然后文件内容为实现类全路径名:
这里是上面两个Dog和Cat实现类

com.test.Cat
com.test.Dog

一般情况下是要将当前工程打包成jar包方式供其它三方进行引用,这里为了简单就只在同一个工程下演示了。

4、接口调用
调用通过JDK提供的工具类ServiceLoader来完成

        ServiceLoader<Animal> serviceLoader = ServiceLoader.load(Animal.class);serviceLoader.forEach(Animal::sayHello);

这里最后Cat和Dog两个实现类的sayHello方法都会被调到。

5、原理分析
读取就不用说了,就是根据接口全名读取其对应的配置文件。然后加载类是通过Class.forName方式

       private S nextService() {if (!hasNextService())throw new NoSuchElementException();String cn = nextName;nextName = null;Class<?> c = null;try {//加载classc = Class.forName(cn, false, loader);} catch (ClassNotFoundException x) {fail(service,"Provider " + cn + " not found");}if (!service.isAssignableFrom(c)) {fail(service,"Provider " + cn  + " not a subtype");}try {//实例化S p = service.cast(c.newInstance());providers.put(cn, p);return p;} }

这里看到是调用无参构造函数进行实例化。

使用Java SPI 可以在不引入任何三方框架前提下实现解耦,接口的定义与具体业务实现分离开来。并且在不改变原逻辑情况下,通过修改配置实现类来修改实现。
但是SPI也有一定的缺陷,不能按需加载只能全量扫描加载。例如上面我们配置了两个实现类,一次都会扫描加载。也不够灵活,不能通过一些条件去更精确的加载自己想要的服务实现类。

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

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

相关文章

【使用教程】在Ubuntu下PMM60系列一体化伺服电机通过SDO跑循环同步位置模式详解

本教程将指导您在Ubuntu操作系统下使用SDO&#xff08;Service Data Object&#xff09;来配置和控制PMM60系列一体化伺服电机以实现循环同步位置模式。我们将介绍必要的步骤和命令&#xff0c;以确保您能够成功地配置和控制PMM系列一体化伺服电机。 01.准备工作 在正式介绍之…

一种更具破坏力的DDoS放大攻击新模式

近日&#xff0c;内容分发网络&#xff08;CDN&#xff09;运营商Akamai表示&#xff0c;一种使网站快速瘫痪的DDoS放大攻击新方法正在被不法分子所利用。这种方法是通过控制数量巨大的中间设备&#xff08;middlebox&#xff0c;主要是指配置不当的服务器&#xff09;&#xf…

【VR】【Unity】白马VR课堂系列-VR开发核心基础03-项目准备-VR项目设置

【内容】 详细说明 在设置Camera Rig前,我们需要针对VR游戏做一些特别的Project设置。 点击Edit菜单,Project Settings,选中最下方的XR Plugin Management,在右边面板点击Install。 安装完成后,我们需要选中相应安卓平台下的Pico VR套件,关于怎么安装PICO VR插件,请参…

PyCharm运行Nosetests并导出测试报告

1. Pycharm运行Nosetests PyCharm可以使用两种方法&#xff0c;运行Nosetests测试文件&#xff1a; 1) 图形用户界面GUI a) 在PyCharm中&#xff0c;选中测试文件&#xff0c;如Tests/test_demo.py b) 鼠标右键选择Run Nosetests in test_demo.py即可执行测试 注1&#xff…

Python 自定义模块和包设计英语生词本(文件版)

上一篇&#xff1a;Python 自定义包和模块随机生成6位验证码&#xff08;详解版&#xff09;-CSDN博客 紧接上一篇博文&#xff0c;当我们熟练掌握如何自定义模块和包后&#xff0c;就要开始着手运用模块和包设计自己的小程序。这里我以“英语生词本”为例&#xff0c;来看我如…

vue 请求代理 proxy

目录 为什么需要配置代理 什么是同源策略 如何配置代理 请求代理的原理 举例说明 为什么需要配置代理 因为浏览器的同源策略&#xff0c;当向和本地 devServer 服务器不同源的地址发送请求&#xff0c; 会违反浏览器的同源策略&#xff0c;导致发送失败&#xff0c;所以需…

极简c++(4)类的静态成员

静态数据成员 ::是作用域操作符&#xff01; #include<iostream> using namespace std;class Point{private:int x,y;public:point(int x 0,int y 0):x(x),y(y){}~point();int getX(){return x;}int getY(){return x;} }假设需要统计点的个数&#xff0c;考虑添加一个…

【MySQL】聚合查询与分组查询

我们先重建一个test库&#xff0c;在test库里新建一个people表&#xff08;包含序列号&#xff0c;姓名&#xff0c;工资&#xff09;&#xff0c;再往表该表里新增六条数据&#xff1a; mysql> drop database if exists test; Query OK, 1 row affected (0.07 sec)mysql>…

【mfc/VS2022】计图实验:绘图工具设计知识笔记

绘制曲线&#xff08;贝塞尔曲线&#xff09;&#xff1a; 转自&#xff1a;CDC 类 | Microsoft Learn 绘制一条或多条贝塞尔曲线。 BOOL PolyBezier(const POINT* lpPoints,int nCount);参数 lpPoints 指向包含曲线端点和控制点的 POINT 数据结构数组。 nCount 指定 lpPo…

git 如何删除本地分支且并没有完全合并到目标分支中

git 如何删除本地分支且并没有完全合并到目标分支中 确保你当前所在的分支不是dev_welc_share_permission分支&#xff0c;如果是的话&#xff0c;可以执行以下命令切换到其他分支&#xff08;比如master&#xff09;&#xff1a; git checkout master使用以下命令删除dev_s…

使用kaliber与imu_utils进行IMU、相机+IMU联合标定

目录 1 标定工具编译 1.1 IMU标定工具 imu_utils 1.2 相机标定工具 kaliber 2 标定数据录制 3 开始标定 3.1 IMU标定 3.2 相机标定 3.3 相机IMU联合标定 4 将参数填入ORBSLAM的文件中 1 标定工具编译 1.1 IMU标定工具 imu_utils 标定IMU我们使用imu_utils软件进行标定…

router和route的区别?

router&#xff08;路由器&#xff09;和route&#xff08;路由&#xff09;是计算机网络中的两个概念&#xff0c;它们有不同的含义和作用。 Router&#xff08;路由器&#xff09;&#xff1a; 路由器是一种网络设备&#xff0c;用于连接多个网络&#xff0c;并在网络之间转发…

如何使用前端包管理器(如npm、Yarn)?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

Linux CentOS8安装gitlab_ce步骤

1 下载安装包 wget --content-disposition https://packages.gitlab.com/gitlab/gitlab-ce/packages/el/8/gitlab-ce-15.0.2-ce.0.el8.x86_64.rpm/download.rpm2 安装gitlab yum install policycoreutils-python-utilsrpm -Uvh gitlab-ce-15.0.2-ce.0.el8.x86_64.rpm3 更新配…

在conda创建的虚拟环境中安装jupyter以及使用

1. 进入你的虚拟环境 conda activate conda_env_name 2. 安装jupyter notebook conda install -y jupyter 3. 启动jupyter jupyter notebook 4. 将conda环境添加到jupyter的内核中 conda install ipykernel python -m ipykernel install --name conda_env_namepython -m…

Stm32_标准库_12_串口_发送数据

波特率&#xff1a;约定的传输速率&#xff0c;1000bps,1s发1000位 引脚 结构 数据帧的传输特点 代码&#xff1a; #include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h"GPIO_InitTypeDef GPIO_InitStruct; USART…

2023年建筑电工(建筑特殊工种)证考试题库及建筑电工(建筑特殊工种)试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年建筑电工(建筑特殊工种)证考试题库及建筑电工(建筑特殊工种)试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特种设备作业人…

【算法-动态规划】两个字符串的删除操作-力扣 583

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…

Idea创建springboot工程的时候,发现pom文件没有带<parent>标签

今天创建springboot工程&#xff0c;加载maven的时候报错&#xff1a; 这个问题以前遇到过&#xff0c;这是因为 mysql-connector-j 没有带版本号的原因&#xff0c;但是springboot的依赖的版本号不是都统一交给spring-boot-starter-parent管理了吗&#xff0c;为什么还会报错&…

Redis 集群 Redis 事务 Redis 流水线 Redis 发布订阅 Redis Lua脚本操作

Redis 集群 & Redis 事务 & Redis 流水线 & Redis 发布订阅 Redis 集群linux安装redis主从配置查看当前实例主从信息 Redis Sentinelsentinel Redis Cluster Redis 事务Redis 流水线Redis 发布订阅Redis Lua脚本操作 Redis 集群 linux安装redis 下载安装包&#…