目录
- 如何解释
- 简单概括
- SPI 和 API
- SPI 实现原理(重要-线程上下文类加载器)
- 如何使用
- 一个Demo
- 功能介绍
- 使用效果(直接在本地模拟服务商提供服务)
- 使用效果(通过 jar 的方式引入)
- 应用分析
- 参考文章
如何解释
简单概括
- 全称 Service Provider Interface,其实是一种插件思想,是一种面向接口编程的思想,即 先定义好一组接口功能,让其他用户/服务提供商 实现该功能,然后自己直接调用 别人实现的功能
SPI 和 API
- API,是开发商先写好实现类,对外提供接口,客户再使用(api 是站在开发者的角度说的)
- SPI,是客户先定义好接口,然后开发商编写该接口的实现类,客户再使用(spi是站在客户的角度说的)
SPI 实现原理(重要-线程上下文类加载器)
- spi 的实现主要依赖
类加载器 + 线程上下文类加载器
,简单来说,其他服务商提供 对应的的实现类.class,客户只需要使用 类加载器加载这些类就可以使用了,但是 现有的 双亲委派模型下 是不支持的。- 前提
子加载器所加载的类能够访问父加载器所加载的类。(双亲委派运行机制)
父加载器所加载的类无法访问到子加载器所加载的类。
- 借助
线程上下文类加载器(Context Classloader)
可以实现 父加载器访问子加载器 加载的类- 在双亲委托模型下,类加载是由下至上的,即下层的类加载器会委托上层进行加载。
- 但是对于SPI来说,有些接口是Java核心库所提供的,而Java核心库是由启动类加载器来加载的,而这些接口的实现却来自于不同的jar包(厂商提供), Java的启动类加载器是不会加载其他来源的jar包,这样传统的双亲委托模型就无法满足SPI的要求。
- 而通过给当前线程设置上下文类加载器,就可以由设置的上下文类加载器来实现对于接口实现类的加载。
如何使用
- 在
ClassPath
下需要一个目录:META/services
- 目录里放一个配置文件
文件名
:需要扩展的接口的 全限定接口名文件内容
:已经实现的类的 全限定类名(包名+基础类名)
- 通过
java.util
包里的ServiceLoad()
方法动态加载 需要的实现类
一个Demo
功能介绍
- 自己的程序提供 Search 接口,其他服务商实现 多种搜索,包括:FileSearch, DatabaseSearch
- 在自己的程序里通过 SPI 使用服务商实现的 FileSearch, DatabaseSearch
使用效果(直接在本地模拟服务商提供服务)
使用效果(通过 jar 的方式引入)
- 埋坑…
应用分析
- jdbc, spring, jar,
- 埋坑…
参考文章
- https://juejin.cn/post/6998044832199344142
- https://pdai.tech/md/java/advanced/java-advanced-spi.html
- https://zhuanlan.zhihu.com/p/28909673