# spi-guo **Repository Path**: luyaguo/spi-guo ## Basic Information - **Project Name**: spi-guo - **Description**: spi demo and note - **Primary Language**: Java - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-07-16 - **Last Updated**: 2023-07-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # SPI ## 一、什么是 SPI SPI的全名为Service Provider Interface.大多数开发人员可能不熟悉,因为这个是针对厂商或者插件的。在java.util.ServiceLoader的文档里有比较详细的介绍。简单的总结下java spi机制的思想。我们系统里抽象的各个模块,往往有很多不同的实现方案,比如日志模块的方案,xml解析模块、jdbc模块的方案等。面向的对象的设计里,我们一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。一旦代码里涉及具体的实现类,就违反了可拔插的原则,如果需要替换一种实现,就需要修改代码。为了实现在模块装配的时候能不在程序里动态指明,这就需要一种服务发现机制。 java spi就是提供这样的一个机制:为某个接口寻找服务实现的机制。有点类似IOC的思想,就是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要。 ## 二、JDBC 中的 SPI jdbc4.0以前, 开发人员还需要基于Class.forName("xxx")的方式来装载驱动,jdbc4也基于spi的机制来发现驱动提供商了,可以通过META-INF/services/java.sql.Driver文件里指定实现类的方式来暴露驱动提供者. ![img](https://img2020.cnblogs.com/blog/1911569/202104/1911569-20210429154713188-1753273885.png) 現在的我們获取JDBC的connection ![img](https://img2020.cnblogs.com/blog/1911569/202104/1911569-20210429155118276-1167166219.png) DriverManager 在初始化前会调用如下方法 ![img](https://img2020.cnblogs.com/blog/1911569/202104/1911569-20210429154946498-1947412360.png) **2、SPI的使用** ![img](https://img2020.cnblogs.com/blog/1911569/202104/1911569-20210429160740814-1610440345.png) ![img](https://img2020.cnblogs.com/blog/1911569/202104/1911569-20210429160944793-144173531.png) 在该文件中添加实现类: ``` com.jalja.data.spi.video.TencentVideo com.jalja.data.spi.video.AiqiyiVideo ``` ![img](https://img2020.cnblogs.com/blog/1911569/202104/1911569-20210429161130311-445916801.png) ## 三、SPI 的原理 使用当前线程的类加载器去加载 ![img](https://img2020.cnblogs.com/blog/1911569/202104/1911569-20210429161323293-1968931010.png) 使用反射创建各个实现类的实例 ![img](https://img2020.cnblogs.com/blog/1911569/202104/1911569-20210429161529408-613129697.png) ## 四、Dubbo 中的 SPI 首先,从上面的java spi的原理中可以了解到,java的spi机制有着如下的弊端: - 只能遍历所有的实现,并全部实例化。 - 配置文件中只是简单的列出了所有的扩展实现,而没有给他们命名。导致在程序中很难去准确的引用它们。 dubbo作为一个高度可扩展的rpc框架,也依赖于java的spi,并且dubbo对java原生的spi机制作出了一定的扩展,使得其功能更加强大。dubbo的spi有如下几个概念: - 扩展点:一个接口。 - 扩展:扩展(接口)的实现。 - 扩展点加载器:ExtensionLoader - 扩展自适应实例:其实就是一个Extension的代理,它实现了扩展点接口。在调用扩展点的接口方法时,会根据实际的参数来决定要使用哪个扩展。dubbo会根据接口中的参数,自动地决定选择哪个实现。 ![img](https://img2020.cnblogs.com/blog/1911569/202104/1911569-20210429164502148-461476120.png) - @SPI:该注解作用于扩展点的接口上,表明该接口是一个扩展点。 - @Adaptive:@Adaptive注解用在扩展接口的方法上。表示该方法是一个自适应方法。Dubbo在为扩展点生成自适应实例时,如果方法有@Adaptive注解,会为该方法生成对应的代码。 [Dubbo SPI 文档 ](https://dubbo.apache.org/zh/docs/v2.7/dev/source/dubbo-spi/#m-zhdocsv27devsourcedubbo-spi)