简述

全程Service Provide Interface,是Java中提供的一种服务发现机制

  • 它允许应用程序动态地加载和使用第三方提供的服务实现
  • 而无需在代码中显示引用这些实现类

Java SPI是基于接口编程思想的具体体现,通过服务接口和其实现分离,从而具备更好的可扩展性和可维护性

如何定义一个SPI

  1. 定义一个接口

    1
    2
    3
    4
    package com.wereash.spi;
    public interface SayService(){
    void say();
    }
  2. 提供一个或多个实现了该接口的实现类,作为服务提供者

    1
    2
    3
    4
    5
    6
    7
    8
    package com.wereash.spi;

    public class SayChinese implements SayService{
    @Override
    public void say(){
    System.out.println("你好");
    }
    }
  3. 配置文件。在src/main/resource下新建META-INF/services目录,同时新增一个以接口的权限定名:com.wereash.spi.SayService命名的文件,内容是要应用的实现类的全限定名,注意,每个实现类的全限定名占据一行

    1
    2
    com.wereash.spi.SayChinese;
    com.wereash.spi.SayEnglish;
  4. 使用ServiceLoader来加载该接口下提供的服务者

    1
    2
    3
    4
    5
    6
    public static void main(String[] args)throws IOException,InterruptedException{
    ServiceLoader<SayService> loaders=ServiceLoader.load(SayService.class);
    for(SayService sayService:loaders){
    sayService.say();
    }
    }

实现原理

  1. 调用ServiceLoader.load()方法会先创建一个新的ServiceLoader,并实例化类中的成员变量
  2. 调用iterator()方法获取一个迭代器对象:
    • ServiceLoader会判断providers对象是否有缓存实例对象,如果存在则直接返回
    • 如果不存在,则执行类的加载操作:
      • 读取META-INF/services/+指定接口的全限定名下的配置文件,获取所有能被实例化的类的全类限定名
      • 通过反射加载并实例化类对象放在provides缓存中
      • 返回该实例对象