JDBC【3】-- SPI技术使用以及在数据库连接中的使用
1.SPI是什么?
SPI
,即是Service Provider Interface
,是一种服务提供(接口实现)发现机制,可以通过ClassPath路径下的META-INF/Service
文件查找文件,加载里面定义的类。
一般可以用来启用框架拓展和替换组件,比如在最常见的数据库连接JDBC中,java.sql.Driver
,不同的数据库产商可以对接口做不一样的实现,但是JDK怎么知道别人有哪些实现呢?这就需要SPI
,可以查找到接口的实现,对其进行操作。
用两个字解释:解耦。
2.如何使用SPI来提供自定义服务?
SPI-Project
:maven
项目DBInterface
:maven
项目,parent是SPI-Project
,定义了一个接口com.aphysia.sqlserver.DBConnectionService
,自己不做实现。MysqlConnection
:prarent是SPI-Project
,实现了接口DBConnectionService
,也就是MysqlConnectionServiceImpl
SqlServerConnection
:prarent 也是SPI-Project
,实现了DBConnectionService
,也就是SqlServerConnectionServiceImpl
WebProject
:测试项目,模拟web项目里面使用数据库驱动。
不管是MySqlConnection
还是SqlServerConnection
两个module中,都是去实现了DBInterface
的接口,并且在resource/META-INF/services
下都需要声明所实现的类,文件名就是实现的接口全限定名com.aphysia.sql.DBConnectionService
,文件里面就是具体的实现类的全限定名,比如:com.aphysia.mysql.MysqlConnectionServiceImpl
SPI-Project的pom文件:
2.1 DBInterface定义接口
DBInterface是SPIProject的一个module,主要是定义一个规范(接口),不做任何实现。
pom文件如下:
定义的接口(模拟了java提供的数据库驱动的情景,定义了驱动规范):DBConnectionService.java
2.2 模拟Mysql实现驱动
接口的第一种实现,相当于模拟第三方Mysql
对接口做了自己的拓展:
pom文件:
实现了前面定义的接口:
MysqlConnectionServiceImpl
声明实现,在resource/META-INF.services/
下定义一个文件,名为com.aphysia.sql.DBConnection
,里面内容是:
2.3 模拟SqlServer实现驱动
SqlServerConnection
也是一个module,pom文件如下:
接口的第二种实现,相当于第三方SqlServer
对接口做了自己的拓展:SqlServerConnectionServiceImpl
声明实现,在resource/META-INF.services/
下定义一个文件,名为com.aphysia.sql.DBConnection
,里面内容是:
2.4 模拟用户使用不同驱动
上面两种不同的接口实现,注意需要在resource下声明,文件名是基类的全限定名,里面内容是具体实现类的全限定名
而我们自己使用项目的时候呢?肯定是需要哪一个驱动就引入哪一个驱动的jar包。
比如我们在webProject中导入两种实现:MysqlConnection
和SqlServerConnection
:
测试代码如下:
输出:
如果我们只在pom文件里面引入mysql的实现呢?答案很明显,只会输出下面一句:
也就是对于使用的人来说,不需要自己再做什么操作,只需要把包引入进来即可,简单易用。
具体完整代码: https://github.com/Damaer/DemoCode/tree/main/SPI-Project,仅供参考
3. ServiceLoader实现原理
ServiceLoader
位于java.util
包下,其主要代码如下:
我们调用ServiceLoader.load()
获取接口的实现,实际上也是调用了 ServiceLoader(Class<S> svc, ClassLoader cl)
,里面都是调用reload()
,reload()
里面做了些什么操作呢?
先把provider
清空,然后创建了LazyIterator
对象,LazyIterator
是一个内部类,实现了Iterator
接口,实际上就是一个懒加载的迭代器。什么时候加载呢?
在迭代器调用的时候,调用hasNextService()
,去解析resource/META-INF/services
下面的实现,并完成实现类的实例化。这里的实例化是使用反射,也是通过全限定类名。class.forName()
。
解析的时候,每一行代表一个实现类,将已经发现的接口进行缓存,放到private LinkedHashMap<String,S> providers
中,同时对外提供遍历迭代的方法。
4. SPI的应用
我们在使用mysql驱动的时候,在mysql-connector-java-version.jar
中,有一个文件是Resource/service/java.sql.Driver
文件,里面记录的是:
也就是声明了java.sql.Driver
的实现类是com.mysql.jdbc.Driver
,不需要手动使用Class.forName()
手动加载。
同样的,slf4j
也是一样的机制去实现拓展功能。
这种思想,通过服务约定-->服务实现-->服务自动注册-->服务发现和使用,完成了提供者和使用方的解耦,真的很强...
此文章仅代表自己(本菜鸟)学习积累记录,或者学习笔记,如有侵权,请联系作者删除。人无完人,文章也一样,文笔稚嫩,在下不才,勿喷,如果有错误之处,还望指出,感激不尽~
技术之路不在一时,山高水长,纵使缓慢,驰而不息。
公众号:秦怀杂货店
__EOF__

本文链接:https://www.cnblogs.com/Damaer/p/13992170.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库