电商的网站有几个,新浪网网站的建设费用预算,网站方案设计与论证,商丘seoSPI机制详解
什么是SPI机制#xff1f;
SPI#xff1a;Service Provider Interface#xff0c;中文直译#xff1a;服务提供者接口#xff0c;它通过在ClassPath路径下的META-INF/service文件夹中查找文件#xff0c;并自动加载文件里所定义的类 在面向对象的设计原则…SPI机制详解
什么是SPI机制
SPIService Provider Interface中文直译服务提供者接口它通过在ClassPath路径下的META-INF/service文件夹中查找文件并自动加载文件里所定义的类 在面向对象的设计原则中一般推荐模块之间基于接口编程通常情况下调用方模块是不会感知到被调用方模块的内部具体实现。一旦代码里面涉及具体实现类就违反了开闭原则。如果需要替换一种实现就需要修改代码。 为了实现在模块装配的时候不用在程序里面动态指明这就需要一种服务发现机制。Java SPI 就是提供了这样一个机制为某个接口寻找服务实现的机制。这有点类似 IoC 的思想将装配的控制权移交到了程序之外。 SPI机制的出现是为了解决什么问题
举个经典的栗子在后端开发中不可避免的就是通过JDBC去连接数据库但是不同的数据库有不同的驱动MySQL有MySQL的驱动Oracle有Oracle的驱动但是它们都实现了JDBC接口 假如现在有个需求项目原来使用的是MySQL作为数据库但是现在要替换成Oracle数据库怎么实现
去项目中手动去改变Driver的实现类
Driver driver new OracleDriverImpl();太不优雅了太不体面了
有没有一种方法能动态替换实现类如果我现在导入的Jar包是MySQL的驱动我就将Driver的实现类定义为MySQL的驱动包导入的Jar包是Oracle的驱动我就将Driver的实现类定义为Oracle的驱动包
诶Java开发者定义了这样一个规则在项目的ClassPath目录中创建META-INF/Services目录在这里面创建以接口名为文件名内容为实现类的全限定名的一个文件 再通过IO的方式获取到所有的全限定名如果存在MySQL数据库的驱动那么calssNameList [“com.mysql.cj.jdbc.Driver”]
以下代码为伪代码,在java.util.ServiceLoader#load(Class clazz) 完成了spi 的实现具体的思想跟下面的流程类似感兴趣的可以去看一看 SPI这种方式可以很好解决不同框架之间的拓展问题可以同时兼容同一个接口的多个实现类
SPI机制的变种
学过SpringBoot的童鞋们都知道自动装配绝对是SpringBoot的大招它可以将外部框架的配置类动态的加载到我们IOC的容器中其实它的思想与SPI机制非常类似
以mybatis-plus为例 问题因为mybatis-plus的ClassPath与我们的项目路径不同肯定是不能通过扫描注解的方式注入到IOC中
那么SpringBoot定义了一个机制如果这些框架想将自己的配置类注入到使用者的IOC中你可以在框架包的ClassPath下创建一个META-INF目录在这个目录中创建一个spring.factories文件 在SpringBoot项目启动时会加载所有Jar包下META-INF/spring.factories文件根据org.springframework.boot.autoconfigure.EnableAutoConfiguration后面的全限定类名通过反射将这个类加载到IOC的容器中
这样就达到了项目与框架之间的解耦在项目不需要手动去将这些框架的配置类加载到IOC容器中
除了SpringBoot的自动装配体现了SPI的思想还有例如Dubbo、Slf4j等等
总结
SPI机制能够使接口与具体的实现类解耦可以根据实际的业务情况启用或替换具体组件SPI机制为很多框架的拓展提供了可能SPI机制更多的是一种思想
如果觉得本篇文章对于您有帮助可否点个小赞篇幅较长建议收藏关注一手等待后续更新更多干货 参考视频https://www.bilibili.com/video/BV1E44y1N7Nk/?spm_id_from333.337.search-card.all.clickvd_source835177d483a47b8fcf9934ddad59626a 参考文章https://javaguide.cn/java/basis/spi.html