聊聊Java的SPI机制
什么是SPI
SPI:Service Provider Interface
官方定义:直译过来是服务提供者接口,学名为服务发现机制,它通过在ClassPath 路径下的META-INF/services文件夹中查找文件,并自动加载文件里所定义的类。
应用场景
JDBC
不同的驱动由不同数据库厂商实现,但因为java中提供驱动的是一个接口,不可以直接实例化,所以要想实例化接口,必须要知道这个接口的全限定名。然后通过反射或其他方式来构建实例进而调用具体的方法。
于是java开发者们想了这样一个方法在项目下的ClassPath目录中创建META-INF/services文件夹,并在这个创建以接口名为文件夹、以类全限定名为文件内容的文件。然后就可以通过IO获取到所有的全限定名。
SpringBoot自动装配
问题
SpringBoot会将当前包及其子包下的bean注入到ioc中,但此时如果其他框架需要将bean注入到ioc中,因为包名是不相同的,所以不能通过扫描注入,而且在注入的过程中要和项目尽可能的解耦。
所以SpringBoot规定了在ClassPath目录下META-INF文件夹中可以定义spring.factories的文件,在项目启动时会遍历所有jar包下的spring.factories文件这样就可以将spring.factories文件中定义的类加载到ioc中。
Dubbo
自定义类加载器 +策略模式
Dubbo中SPI的基本流程与使用
Dubbo中AOP的源码实现
Dubbo中的依赖注入的源码实现
Dubbo中的Adaptive扩展点的源码实现5. Dubbo中的Activate扩展点的源码实现
总结
SPI机制能够使接口与具体的实现类解耦,
可以根据实际的业务情况启用或替换具体组件。
SPI机制为很多框架的扩展提供了可能。
SPI机制更多的是一种思想。
参考:https://www.bilibili.com/video/BV1E44y1N7Nk
题外话
那么策略模式和 SPI 机制到底有什么区别呢?
如果从代码接入的级别来看,策略模式还是在原有项目中进行代码修改,只不过它不会修改原有类中的代码,而是新建了一个类。而 SPI 机制则是不会修改原有项目中的代码,其会新建一个项目,最终以 Jar 包引入的方式代码。
从这一点来看,无论策略模式还是 SPI 机制,他们都是将修改与原来的代码隔离开来,从而避免新增代码对原有代码的影响。但策略模式是类层次上的隔离,而 SPI 机制则是项目框架级别的隔离。
从应用领域来说,策略模式更多应用在业务领域,即业务代码书写以及业务代码重构。而 SPI 机制更多则是用于框架的设计领域,通过 SPI 机制提供的灵活性,让框架拥有良好的插件特性,便于扩展。
总结一下,策略模式与 SPI 机制有下面几点异同:
- 从设计思想来看。策略模式和 SPI 机制其思想是类似的,都是通过一定的设计隔离变化的部分,从而让原有部分更加稳定。
- 从隔离级别来看。策略模式的隔离是类级别的隔离,而 SPI 机制是项目级别的隔离。
- 从应用领域来看。策略模式更多用在业务代码书写,SPI 机制更多用于框架的设计。