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编辑  收藏  举报

导航