一、什么是SPI机制
SPI ,全称为 Service Provider Interface,是一种服务发现机制。它通过在ClassPath路径下的META-INF/services文件夹查找文件,自动加载文件里所定义的类。

这一机制为很多框架扩展提供了可能,比如在Dubbo、JDBC中都使用到了SPI机制。
JDBC的设计,jdk提供了一个接口java.sql.Driver,通常各大厂商(如Mysql、Oracle)会根据一个统一的规范(java.sql.Driver)开发各自的驱动实现逻辑。客户端使用jdbc时不需要去改变代码,直接引入不同的spi接口服务即可。

二、SPI机制的主要目的

  • 为了解耦,将接口和具体实现分离开来;
  • 提高框架的扩展性。以前写程序的时候,接口和实现都写在一起,调用方在使用的时候依赖接口来进行调用,无权选择使用具体的实现类。

三、SPI机制案例

  • JDBC驱动加载案例:利用Java的SPI机制,我们可以根据不同的数据库厂商来引入不同的JDBC驱动包;
  • SpringBoot的SPI机制:我们可以在spring.factories中加上我们自定义的自动配置类,事件监听器或初始化器等;
  • Dubbo的SPI机制:Dubbo更是把SPI机制应用的淋漓尽致,Dubbo基本上自身的每个功能点都提供了扩展点,比如提供了集群扩展,路由扩展和负载均衡扩展等差不多接近30个扩展点。如果Dubbo的某个内置实现不符合我们的需求,那么我们只要利用其SPI机制将我们的实现替换掉Dubbo的实现即可。

例子:
接口

public interface SPIService {
    void execute();
}

实现类1

public class SpiImpl1 implements SPIService{
    public void execute() {
        System.out.println("SpiImpl1.execute()");
    }
}

实现类2

public class SpiImpl2 implements SPIService{
    public void execute() {
        System.out.println("SpiImpl2.execute()");
    }
}

最后呢,要在ClassPath路径下配置添加一个文件。文件名字是接口的全限定类名,内容是实现类的全限定类名,多个实现类用换行符分隔

spring的spi spring的spi机制_开发语言

com.example.test.demo.spi.SpiImpl1
com.example.test.demo.spi.SpiImpl2

测试:

public static void main(String[] args) {
//        Service.providers方法拿到实现类的实例
        Iterator<SPIService> providers = Service.providers(SPIService.class);
        while(providers.hasNext()){
            SPIService ser=providers.next();
            ser.execute();
        }
        System.out.println("==============================================");
//      通过ServiceLoader.load方法拿到实现类的实例 
//  	ServiceLoader是实现SPI一个重要的类。是Mark Reinhold在java1.6引入的类,为了解决接口与实现分离的场景。
        ServiceLoader<SPIService> load = ServiceLoader.load(SPIService.class);
        Iterator<SPIService> iterator = load.iterator();
        while(iterator.hasNext()){
            SPIService next = iterator.next();
            next.execute();
        }
    }

结果:

SpiImpl1.execute()
SpiImpl2.execute()
==============================================
SpiImpl1.execute()
SpiImpl2.execute()