spi机制是什么
转载自博客:https://blog.csdn.net/qq_32683235/article/details/115523143
一、什么是SPI机制
SPI是Service Provider Interface 的简称,即服务提供者接口的意思。SPI说白了就是一种扩展机制,我们在相应配置文件中定义好某个接口的实现类,然后再根据这个接口去这个配置文件中加载这个实例类并实例化。有了SPI机制,那么就为一些框架的灵活扩展提供了可能,而不必将框架的一些实现类写死在代码里面。
二、SPI机制的主要目的
为了解耦,将接口和具体实现分离开来;
提高框架的扩展性。以前写程序的时候,接口和实现都写在一起,调用方在使用的时候依赖接口来进行调用,无权选择使用具体的实现类。
三、SPI机制案例
JDBC驱动加载案例:利用Java的SPI机制,我们可以根据不同的数据库厂商来引入不同的JDBC驱动包;
SpringBoot的SPI机制:我们可以在spring.factories中加上我们自定义的自动配置类,事件监听器或初始化器等;
Dubbo的SPI机制:Dubbo更是把SPI机制应用的淋漓尽致,Dubbo基本上自身的每个功能点都提供了扩展点,比如提供了集群扩展,路由扩展和负载均衡扩展等差不多接近30个扩展点。如果Dubbo的某个内置实现不符合我们的需求,那么我们只要利用其SPI机制将我们的实现替换掉Dubbo的实现即可。
上面的三个栗子先让我们直观感受下某些框架利用SPI机制是如何做到灵活扩展的
四、如何使用Java的SPI
我们先来看看如何使用Java自带的SPI。先定义一个Developer接口
package com.demo; public interface Plugin { void execute(); }
接下来是两个实现类
package com.demo; public class PluginA implements Plugin { @Override public void execute() { System.out.println("PluginA.execute is done"); } }
package com.demo; public class PluginB implements Plugin { @Override public void execute() { System.out.println("PluginB.execute is done"); } }
然后再在项目resources目录下新建一个META-INF/services文件夹,然后再新建一个以Plugin 接口的全限定名命名的文件,文件内容为:
com.demo.PluginA
com.demo.PluginB
最后我们再新建一个测试类JdkSPITest:
package com.demo; import java.util.Iterator; import java.util.ServiceLoader; public class PluginTest { public static void main(String[] args) { ServiceLoader<Plugin> serviceLoader=ServiceLoader.load(Plugin.class); Iterator<Plugin> itre = serviceLoader.iterator(); while(itre.hasNext()){ //itre.next() 这行代码会对 SPI 装备的完成类进行初始化 itre.next().execute(); } } }
程序的运行结果如下
二、SPI机制的主要目的
为了解耦,将接口和具体实现分离开来;
提高框架的扩展性。以前写程序的时候,接口和实现都写在一起,调用方在使用的时候依赖接口来进行调用,无权选择使用具体的实现类。
三、SPI机制案例
JDBC驱动加载案例:利用Java的SPI机制,我们可以根据不同的数据库厂商来引入不同的JDBC驱动包;
SpringBoot的SPI机制:我们可以在spring.factories中加上我们自定义的自动配置类,事件监听器或初始化器等;
Dubbo的SPI机制:Dubbo更是把SPI机制应用的淋漓尽致,Dubbo基本上自身的每个功能点都提供了扩展点,比如提供了集群扩展,路由扩展和负载均衡扩展等差不多接近30个扩展点。如果Dubbo的某个内置实现不符合我们的需求,那么我们只要利用其SPI机制将我们的实现替换掉Dubbo的实现即可。
上面的三个栗子先让我们直观感受下某些框架利用SPI机制是如何做到灵活扩展的。
我们来看一个真实的使用上述SPI的例子—数据库驱动(Driver)。
我们知道,当我们的项目里面使用引用了mysql的驱动pom依赖时,我们的项目里面会自动选择使用mysql的驱动,我们甚至不需要手动去加载。我们来看看它的具体实现。
1、首先看一下java.sql.Driver的类,这里面也是相当于定义了一个规范
2、其次看mysql驱动包的META-INF/services文件夹下面有没有指定的文件
很熟悉,命名就是java.sql.Driver
3、打开文件查看一下文件内容
这里面就能看到我们的mysql的驱动了,到这里基本上就确认这也是使用SPI实现的,顺便说一下,现在为什么我们不需要使用Class.forName()去加载驱动了,这是因为DriverManager使用SPI的机制已经帮我们加载好了,我们来看看DriverManager的类
不管是文件名还是文件内容都是全限定名,所以通过反射很容易创建相应的类
在现有框架中的使用
其实了解SPI机制是因为最近看SpringBoot代码的时候发现的,我们知道在SprngBoot中好多的配置和实现都有默认的实现,我们只需要修改部分配置,比如数据库配置,我们只要在配置文件中写上对应的url,username,password就可以使用了。其实他这边用的就是SPI的方式实现的
不过Spring使用的只是和JDK中的原理相同而已。
JDK使用的工具类是ServiceLoader
Spring中使用的类是SpringFactoriesLoader,在 org.springframework.core.io.support包中
区别:
文件路径不同 spring配置放在 META-INF/spring.factories中
posted on 2024-02-28 19:46 luzhouxiaoshuai 阅读(116) 评论(0) 编辑 收藏 举报