Java SPI机制总结系列之开发入门实例

 

原创/朱季谦

在该文章正式开始前,先对 Java SPI是什么做一个简单的介绍。

SPI,是Service Provider Interface的缩写,即服务提供者接口,单从字面上看比较抽象,你可以理解成,该机制就像Spring容器一样,通过IOC将对象的创建交给了Spring容器处理,若需要获取某个类的对象,就从Spring容器里取出使用即可。同理,在SPI机制当中,提供了一个类似Spring容器的角色,叫【服务提供者】,在代码运行过程中,若要使用到实现了某个接口的服务实现类对象,只需要将对应的接口类型交给服务提供者。服务提供者将会动态加载实现了该接口的所有服务实现类对象。
服务提供者的角色用下图来表示。

image

举一个例子来说明。

假如,假如Maven项目里有这样一个interface接口,接口全名“com.zhu.service.UserService”——

package com.zhu.service;

public interface UserService {
    void getName();
}

创建一个“com.zhu.service.impl.AUserServiceImpl”实现类——

public class AUserServiceImpl implements UserService {
    @Override
    public void getName() {
        System.out.println("这是A用户姓名");
    }
}

接着在resource资源里,创建一个META-INF.services目录,在该目录里,创建一个文件名与接口com.zhu.service.UserService一致的文件——

image

该com.zhu.service.UserService文件里写下com.zhu.service.impl.UserServiceImpl类名字——

image

这时候,就可以基于Java SPI动态加载到接口的实现类并执行了,我们写一个简单的测试类做验证——

public class Test {
    public static void main(String[] args) {
    ServiceLoader<UserService> serviceLoader = ServiceLoader.load(UserService.class);
    Iterator<UserService> serviceIterator = serviceLoader.iterator();
    while (serviceIterator.hasNext()) {
         UserService service = serviceIterator.next();
         service.getName();
    }
}
    }
}

执行该代码,ServiceLoader会加载到META-INF.services目录下的配置文件,找到对应接口全名文件,读取文件里的类名,再通过反射就可以进行实现类的实例化。既然能找到实现类的对象,那么不就可以基于父类引用指向子类对象,进而调用到实现类的getName()方法。该方法里执行打印语句 System.out.println("打印用户姓名"),打印结果如下,说明基于接口UserService,在程序动态加载并执行UserService接口实现。

image

Java SPI的机制玩法,就如上文这一整个过程的实现。

该机制存在一个缺陷,假如该接口对应的文件存在多份实现类,那么,它都会一起执行了。

我们增加多一个实现类BUserServiceImpl——

public class BUserServiceImpl implements UserService {
    @Override
    public void getName() {
        System.out.println("这是B用户姓名");
    }
}

然后,在resource资源里的META-INF.services目录接口对应com.zhu.service.UserService文件里,将BUserServiceImpl实现类的全名增加到文件里——

image

其他原有的代码无需改动,直接执行Test的main方法,打印结果如下,可以看到,新增的BUserServiceImpl实现类的getName()也被运行了。

image

这就说明,Java SPI机制会将文件里配置的所有实现类都动态加载运行,稍微思考了一下,不难发现,若当中某个实现类的getName()出现异常,那么后面还没有执行到的其他实现类就会终止了。

因此,Dubbo框架在设计SPI机制时,只是参考了Java SPI的实现,但没有照搬,相比Java,Dubbo增强了SPI机制,可以针对请求动态得选择需要的接口实现类来运行,更加灵活方便。我在自己的另一边原创博文中,详细介绍过Dubbo SPI的原理,感兴趣的小伙伴可以阅读——《Dubbo2.7的Dubbo SPI实现原理细节》

SPI机制的优点很明显,当我们需要基于已有接口新增一个实现类功能时,只需要新增一个实现类代码,无需在原有代码逻辑上做改动,就可以实现新增类的功能逻辑了。

这种场景比较适合在报表或者处理Excel文档情况下,需针对一个新报表或者Excel做相应定制化处理,只需要基于SPI已有接口新增一个实现类即可。我会在后续文章中,将过去应用到SPI的实践经验做一下总结。

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

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

相关文章

机器学习---lightGBM

1. lightGBM演进过程 AdaBoost是⼀种提升树的方法&#xff0c;和三个臭皮匠&#xff0c;赛过诸葛亮的道理⼀样。 AdaBoost两个问题&#xff1a; (1) 如何改变训练数据的权重或概率分布提高前⼀轮被弱分类器错误分类的样本的权重&#xff0c;降低前⼀ 轮被分对的权重 (2) 如何…

远程登陆利器 ssh

文章目录 远程登陆利器 ssh登陆远程服务器指定用户名多数情况的登陆方式查看服务器的时间指定端口更多信息 远程登陆利器 ssh ssh命令是openssh套件中的客户端连接工具&#xff0c;使用加密协议实现安全的远程登录服务器&#xff0c;实现对服务器的远程管理。 官方定义为&…

[学习笔记]刘知远团队大模型技术与交叉应用L1-NLPBig Model Basics

本节主要介绍NLP和大模型的基础知识。提及了词表示如何从one-hot发展到Word Embedding。语言模型如何从N-gram发展成预训练语言模型PLMs。然后介绍了大模型在NLP任务上的表现&#xff0c;以及它遵循的基本范式。最后介绍了本课程需要用到的编程环境和GPU服务器。 一篇NLP方向的…

还在因为版本不一致重装node吗,用它试试

一、卸载nodejs 首先卸载已安装的nodejs&#xff0c;总体分三步 1)打开控制面板&#xff0c;卸载nodejs 2)打开计算机->高级->环境变量&#xff0c;删除path中nodejs相关的配置 3)打开nodejs安装目录&#xff0c;整体删除 打开cmd&#xff0c;输入以下命令&#xff…

Android Studio下载gradle反复失败

我的版本&#xff1a;gradle-5.1.1 首先检查设置路径是否正确&#xff0c;参考我的修改&#xff01; 解决方案 1.手动下载Gradle.bin Gradle Distributions 下载地址 注意根据编译器提示下载&#xff0c;我这要求下载的是bin 而不是all 2.把下载好的整个压缩包放在C:\Users\…

Uniapp软件库源码-全新带勋章等

测试环境&#xff1a;php7.1。ng1.2&#xff0c;MySQL 5.6 常见问题&#xff1a; 配置好登录后转圈圈&#xff0c;检查环境及伪静态以及后台创建好应用 上传图片不了&#xff0c;检查php拓展fileinfo 以及public文件权限 App个人主页随机背景图&#xff0c;在前端uitl文件夹里面…

数组深入详解

1、什么是数组&#xff1f; Java 语言中提供的数组是用来存储固定大小的同类型元素。 如&#xff1a;可以声明一个数组变量&#xff0c;如 numbers[100] 来代替直接声明 100 个独立变量 number0&#xff0c;number1&#xff0c;…&#xff0c;number99。 注意事项&#xff1a;…

第二百六十六回

文章目录 1. 概念介绍2. 分析与解决2.1 分析问题2.2 解决方案 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何修改CircleAvatar的大小"相关的内容&#xff0c;本章回中将介绍如何修改StatusBar中文字的颜色.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1.…

鸿蒙Harmony-层叠布局(Stack)详解

我们总是为了太多遥不可及的东西去拼命&#xff0c;却忘了人生真正的幸福不过是灯火阑珊处的温暖&#xff0c;柴米油盐的充实&#xff0c;人生无论你赚的钱&#xff0c;是多还是少&#xff0c;经历的事情是好还是坏&#xff0c;都不如过好当下的每一天&#xff01; 目录 一&am…

CF1178F1 Short Colorful Strip 题解

Short Colorful Strip 传送门 题面翻译 题目描述 这是F题的第一个子任务。F1和F2的区别仅在对于m和时间的限制上 有n1种颜色标号从0到n&#xff0c;我们有一条全部染成颜色0的长为m的纸带。 Alice拿着刷子通过以下的过程来给纸带染色&#xff1a; 我们按照从1到n的顺序进…

美国初创公司Rabbit推出口袋AI设备R1;吴恩达课程:使用LangChain.js构建强大的JavaScript应用

&#x1f989; AI新闻 &#x1f680; 美国初创公司Rabbit推出口袋AI设备R1&#xff0c;短时间内被抢购一空 摘要&#xff1a;美国初创公司Rabbit在CES 2024上发布了口袋AI设备R1&#xff0c;这款设备在一天内被抢购一空&#xff0c;售价为199美元。R1具有小巧玲珑的触屏、摄像…

【线性表的基本操作实现及其应用 】

线性表的基本操作实现及其应用 1.实验目的 ⑴ 熟练掌握线性表的基本操作在两种存储结构上的实现&#xff0c;其中以熟悉各种链表的操作为重点。 ⑵ 巩固高级语言程序设计方法与技术&#xff0c;会用线性链表解决简单的实际问题。 2.实验原理与要求 ⑴ 按照数据结构实验任务书&…

【笔记】书生·浦语大模型实战营——第四课(XTuner 大模型单卡低成本微调实战)

【参考&#xff1a;tutorial/xtuner/README.md at main InternLM/tutorial】 【参考&#xff1a;(4)XTuner 大模型单卡低成本微调实战_哔哩哔哩_bilibili-【OpenMMLab】】 总结 学到了 linux系统中 tmux 的使用 了解了 XTuner 大模型微调框架的使用 pth格式参数转Hugging …

【量化交易故事】小明开启了量化创业之旅-01

故事开始于2023年的春天&#xff0c;小明是一位对金融市场充满热情的IT工程师。在经历了数次基于主观判断和个人情绪进行投资却收获平平后&#xff0c;他意识到传统交易方式中的人为因素难以避免&#xff0c;而这往往成为影响投资决策稳定性和准确性的关键障碍。在一次偶然的机…

工作压力测试

每个职场人都会遇到工作压力&#xff0c;在企业人力资源管理的角度来看&#xff0c;没有工作压力是人力资源的低效&#xff0c;适当的工作压力可以促使员工不断进取&#xff0c;然而每个人的抗压能力是不同的&#xff0c;同样的工作量和工作难度&#xff0c;不同的人在面对相同…

【Java语言基础②】Java基本语法——Java程序基本格式,注释,标识符,常量

通过前面的学习&#xff0c;大家对Java语言有了一个基础认识&#xff0c;但现在还无法使用Java语言编写程序&#xff0c;要熟练使用Java语言编写程序&#xff0c;必须充分掌握Java语言的基础知识。今天咱们就来聊一聊Java的基本语法。 1.java程序的基本格式 Java程序代码必须…

在win11中安装“mingw-w64-gcc-13.2-stable-r40”

在windows系统中&#xff0c;安装完VSCode后&#xff0c;还需要安装mingw&#xff0c;才可以使用C和C编译。 1、从MinGW-w64镜像站点&#xff1a;http://files.1f0.de/mingw&#xff0c;下载“mingw-w64-gcc-13.2-stable-r40”&#xff0c;见下图&#xff1a; 2、将“mingw-w6…

Centos7编译Python3.11源码并安装完成的详细教程

Python3.11的Linux源码&#xff1a; Index of /ftp/python/https://www.python.org/ftp/python/由于Centos7里自带的openssl是1.0版本的&#xff0c;而Centos Stream8和9用的是openssl-1.1.1版本的。 注意&#xff1a;openssl必须是openssl-1.1.1版本的&#xff0c;虽然最高版…

【大厂秘籍】 - Java多线程面试题

Java多线程面试题 友情提示&#xff0c;看完此文&#xff0c;在Java多线程这块&#xff0c;基本上可以吊打面试官了 线程和进程的区别 进程是资源分配的最小单位&#xff0c;线程是CPU调度的最小单位 线程是进程的子集&#xff0c;一个进程可以有很多线程&#xff0c;每条线…

10.9.2 std::function 存储函数对象 Page184

41行&#xff0c;pending只是inc的复制品&#xff0c;所以43&#xff0c;44行&#xff0c;不会改变inc()的值 demo_function2()的运行结果&#xff1a; 59行&#xff0c;pending是inc的引用&#xff0c;所以61,62行将会改变inc()的值