这段代码整体逻辑不算复杂 , 所以也有点自信回头 , 就没跑单元测试 , 不过问题应该不大 。解释一下其中具体逻辑:
- FileServiceFactory 大家可以理解为文件服务对外的统一访问入口 。实现了 spirng 初始化的一个接口 , 可以在 bean 初始化时进行代码逻辑操作
- bean 初始化时 , 通过 ServiceLoader 类加载器负责加载对象存储接口 , 这样就能加载到客户端存放到 META-INF/services 中的自定义对象存储实现
- 获取到自定义对象存储后 , 和服务端本身自带的对象存储一起存放至容器中 , 这样就可以根据项目中的 fileStoreType 获取对应的服务了
上面的业务只是为了让不理解 SPI 的小伙伴更好的掌握应用场景 , 其实对象存储服务是一种可穷举的业务场景 , SPI 并不是唯一的解决思路 。当然 , 为了省事使用 SPI 也没啥问题 。最后提一句 , SPI 最合适的还是没有统一业务实现场景 , 就像上面提到过的加密算法
深入解析 SPI一篇技术解析文章 , 适当放一些源码解析感觉会更好一些 。下面一起来看看 ServiceLoader底层都做了什么事情
通过 ServiceLoader 的 load 方法创建一个新的 ServiceLoader , 并实例化其中的成员变量
文章插图
应用程序通过迭代器接口获取对象实例 , 这里首先会判断 providers 对象中是否有实例对象
如果有实例 , 那么就返回;如果没有 , 执行类的装载步骤 , 具体类装载实现如下:
- LazyIterator#hasNextService 读取 META-INF/services 下的配置文件 , 获得所有能被实例化的类的名称 , 并完成 SPI 配置文件的解析
- LazyIterator#nextService 负责实例化 hasNextService() 读到的实现类 , 并将实例化后的对象存放到 providers 集合中缓存
文章插图
如果你不知道上面的一些 "黑话" 不要紧 , 因为都是 ServiceLoader 底层执行的方法 , 跟着下面这个程序敲一遍代码就懂了
文章插图
这里为了跟源码 , 也是把上面对象存储的逻辑 , 简单写了个 SPI 示例 , 证明是没有问题的 。如果小伙伴想真正了解 , 就需要跟下源码去看看 , 其它源码部分就不细说了
结言上面说了很多关于 SPI 机制的优点以及应用场景 , 这里总结下关键内容
- SPI 机制优势就是解耦 。将接口的定义以及具体业务实现分离 , 而不是和业务端全部耦合在一端 。可以实现 运行时根据业务实际场景启用或者替换具体组件
- SPI 机制的场景就是 没有统一实现标准的业务场景 。一般就是 , 服务端有标准的接口 , 但是没有统一的实现 , 需要业务方提供其具体实现 。比如说 JDBC 的 JAVA.sql.Driver 接口和不同云厂商提供的数据库实现包
- 不能按需加载 。虽然 ServiceLoader 做了延迟加载 , 但是只能通过遍历的方式全部获取 。如果其中某些实现类很耗时 , 而且你也不需要加载它 , 那么就形成了资源浪费
- 获取某个实现类的方式不够灵活 , 只能通过迭代器的形式获取 。这两点可以参考 Dubbo SPI 实现方式进行业务优化
梳理出 SPI 的场景以及优势后 , 小伙伴最好再去 Debug 源代码 , 这样会大家对 SPI 的实现才能更加清楚 。只有对一个知识点真正掌握 , 才不至于事后很快遗忘
推荐阅读
- 固伦和孝公主出生时乾隆多大,固伦温宪公主与雍正关系如何
- 不做自媒体,如何在今日头条上每天赚几百
- 自媒体创业者如何去分析平台提供的数据?
- 在今日头条如何才能有收益,做到这几点收益会慢慢的来找你哦
- 正确的泡茶七个步骤,泡茶的步骤
- 春季踏青好时节 如何让健康与你同行
- 干桂花的食用方法窍门,干桂花的食用方法
- 玫瑰香柑的功效与作用,玫瑰花茶的功效与作用
- 应届生|跟应届生谈经验,跟有经验的人谈年龄,原来面试的“套路”真不少
- 微信上如何开票?