ServiceLoader
  • 1.

SPI 全名 Service Provider Interface ,是java提供的 一个 服务接口拓展机制。使用SPI 可以轻松的修改接口的实现方式。

 

例子代码:

创建一个接口:

/**
 * 描述
 *
 * @Author ZHANGYUKUN
 * @Date 2022/6/27
 */
public interface MyInterface {


    String doSome();

}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

  创建2个实现类:

/**
 * 描述
 *
 * @Author ZHANGYUKUN
 * @Date 2022/6/27
 */
public class Impl1 implements MyInterface {
    @Override
    public String doSome() {
        return "Impl1";
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
/**
 * 描述
 *
 * @Author ZHANGYUKUN
 * @Date 2022/6/27
 */
public class Impl2 implements MyInterface {
    @Override
    public String doSome() {
        return "Impl2";
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

  

  

然后再classpath下面创建 META-INF/services 两个目录

在 META-INF/services 里面建一个文件名为接口全称的文件:com.lomi.spi.MyInterface

文件里面写着接口的实现类的全类名:com.lomi.spi.Impl2

SPI  服务提供者接口_接口实现

 

 

 

然后我们通过 ServiceLoader 获取接口实现,可以拿到我们指定接口实现类。

package com.lomi.spi;

import java.util.Iterator;
import java.util.ServiceLoader;

/**
 * 描述
 *
 * @Author ZHANGYUKUN
 * @Date 2022/6/27
 */
public class Main {

    public static void main(String[] args) {
        ServiceLoader<MyInterface> loadedDrivers = ServiceLoader.load(MyInterface.class);
        Iterator<MyInterface> driversIterator = loadedDrivers.iterator();
        while(driversIterator.hasNext()) {
            MyInterface myInterface =   driversIterator.next();

            System.out.println( myInterface.getClass() );
        }

        System.out.println( "over.................");
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.

  

SPI  服务提供者接口_java_02

 

 

 

很多jar都是通过这种方式来切换接口实现类的,比如 SLF4j 导入对应的装换包,就会换成对应的实现, 原理就是 对应的实现包里面 指定了实现类

 

 

 

 

 

 

 

dubbo 的 SPI 也是类似的机制,但是支持  实现key名字=实现类全名格式,,并且可以在接口上指定默认使用那个key对应的实现,获取接口实现类是通过 ExtensionLoader 来获取的

SPI  服务提供者接口_接口实现_03

 

 

获取指定 key 的实现类,和查看有那些实现

public static void main(String[] args) {
    ExtensionLoader<Filter> extensionLoader = ExtensionLoader.getExtensionLoader(Filter.class);

    //获取指定实现
    Filter filter = extensionLoader.getExtension("dubboExceptionFilter");
    System.out.println(filter.getClass());

    //打印有那些实现
    extensionLoader.getSupportedExtensions().forEach((itemKey) -> {
        System.out.println(itemKey);
    });
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

  

如果要在接口上指定默认实现可以使用直接 @SPI(“默认实现的key”)