某厂面试:如何优雅使用 SPI 机制

原文:某厂面试:如何优雅使用 SPI 机制
作者:龙台
代码不多 , 文章可能有点长 。朋友面试某厂问到的 SPI 机制 , 联想到自己项目最近写到的 SPI 场景 , 文章简要描述下 SPI 机制的发展历程
产出背景因为最近项目中使用分库分表以及数据加密使用到了 ShardingSphere , 所以决定这段时间看看源码实现 。问我为什么要读源码?不看源码怎么提高逼格嘞 , 就是这么朴实无华~
考虑到自己看微信文章的习惯 , 不喜欢代码太多的 , 看着逻辑有点不清晰 。所以 , 以后的文章风格就是 , 少贴代码 , 画图 + BB
Sharding-Jdbc SPI看源码的历程 , 往往从点开 Jar 包的瞬间开始 。好巧不巧 , 就看到源代码包下有个 SPI 包 , 处于好奇心就点了一点 , 嗯~ 代码果然很熟悉 , 还是那个配方原来的味道

某厂面试:如何优雅使用 SPI 机制

文章插图
 
看了许久 , 陷入深深的沉思 。内心小九九:这玩意好像之前看过 , 但是在哪我忘了 , 这到底是个啥?
代码还是那个代码 , 只是它认识我 , 我不认识它了
这一块的 SPI 接口是 shrding-jdbc 预留自定义加密器的接口
看到这里相信就遇到过绝大多数技术同学都会遇到的一个问题 , 那就是 认为自己会了 , 实际情况呢?不一定 。所以 , 学习一门技术 , 一定要多看几遍 , 尝试去理解记忆 。千万不要看一遍之后 , 眼高手低认为技术 so easy , 然后隔十天半个月就啥都不记的
 
继续回过头来说说今天的主角:SPI 。首先回答这么一个问题 , 什么是 SPI 机制
SPI 全称为 Service Provider Interface , 是一种服务发现机制 。为了被第三方实现或扩展的 API , 它可以用于实现框架扩展或组件替换
SPI 机制本质是将 接口实现类的全限定名配置在文件中 , 并由服务加载器读取配置文件 , 加载文件中的实现类 , 这样运行时可以动态的为接口替换实现类
看文字描述介绍总是枯燥无味且空洞的 。简单一点来说 , 就是你在 META-INF/services 下面定义个文件 , 然后通过一个特殊的类加载器 , 启动的时候加载你定义文件中的类 , 这样就能扩展原有框架的功能
就这么简单 , 那可能有读者会问:我不定义在 META-INF/services 下面行不行?就想定义在别的地方
 
不行滴 , 请遏制住这么危险的想法 , 人家怎么定义你就怎么实现 。这是 JDK 规定好的配置路径 , 你随便定义 , 类加载器怎么知道去哪里加载
某厂面试:如何优雅使用 SPI 机制

文章插图
 
看到这个 PREFIX 常量之后 , 想法比较活跃的小伙子不知道清醒点了么 。简单画张图来描述下 SPI 的运行机制
某厂面试:如何优雅使用 SPI 机制

文章插图
 
有点 SPI 基础的同学看到图之后应该又开始自信了 , 这不就是我之前看过的那玩意么?是的 , 技术还是那个技术 , 可以继续往下看看 , 有没有自己不知道的
为什么要有 SPI了解一项技术的前提 , 一定要知道它为了解决什么样的痛点而存在 , JDK 作者也不会没屁事加点代码玩
引入了 SPI 机制后 , 服务接口与服务实现就会达成分离的状态 , 可以实现 解耦以及程序可扩展机制 。服务提供者(比如 springboot starter)提供出 SPI 接口后 , 客户端(平常的 springboot 项目)就可以通过本地注册的形式 , 将实现类注册到服务端 , 轻松实现可插拔
数据加密举例以实际项目举个例子 , 就拿 sharding-jdbc 数据加密模块来说 , sharding-jdbc 本身支持 AES 和 MD5 两种加密方式 。但是 , 如果客户端不想用内置的两种加密 , 偏偏想用 RSA 算法呢?难道每加一种算法 , sharding-jdbc 就要发个版本么
sharding-jdbc 可不会这么干 , 首先提供出 Encryptor 加密接口 , 并引入 SPI 的机制 , 做到服务接口与服务实现分离的效果 。如果客户端想要使用新的加密算法 , 只需要在客户端项目 META-INF/services 目录下定义接口的全限定名称文件 , 并在文件内写上加密实现类的全限定名 , 就像这样式的


推荐阅读