什么是SPI机制?
SPI的英文全称为Service Provider Interface,即为服务提供者接口。这个机制简单点理解就是:为某个接口寻找服务实现的机制。
SPI规范
定义服务的通用接口,针对通用的服务接口,提供具体的实现类。
1.在jar包(服务提供者)的META-INF/services/目录中,新建一个文件,文件名为SPI接口的"全限定名"。 文件内容为该接口的具体实现类的"全限定名"。
2.将spi所在jar放在主程序的classpath中。
3.服务调用方使用jdk提供的java.util.ServiceLoader去动态加载具体的实现类到JVM中。
SPI应用
新建一个maven工程,在工程的src/main/resources/META-INF目录下创建services文件夹,如下:

image.png
1.定义接口。

image.png
2.对接口进行实现。

image.png
3.在src/main/resources/META-INF/services目录下创建以接口'全限定名'的文件,把接口的实现类的全类名放到里面,如下:

image.png
编译工程后的文件在jar包下的META-INF/services目录下:

image.png
4.如何使用
建一个工具类SpiUtils,代码如下:
package com.study.rpc.common.tools;
import java.util.ServiceLoader;
/**
* SPI机制 动态扩展
* SPI ,全称为 Service Provider Interface,是一种服务发现机制。
* 它通过在ClassPath路径下的META-INF/services文件夹查找文件,自动加载文件里所定义的类。
* 要在ClassPath路径下配置添加一个文件。文件名字是 接口的全限定类名,内容是实现类的全限定类名,多个实现类用换行符分隔。
*
* Protocol protocol = (Protocol) SpiUtils.getServiceImpl(protocolConfig.getName(), Protocol.class);
*/
public class SpiUtils {
/**
* @param serviceName 实现类的名称
* @param classType 实现类的接口class
* @return 返回需要的实现类的对象
*/
public static Object getServiceImpl(String serviceName, Class classType) {
// 创建具体实现 -- jdk 加载 名称 ,第三方扩展
//resources下 META-INF services 路径下新建一个路径全称的文件,指定的文件接口的实现类
//返回这个接口的所有实现类
ServiceLoader services =
ServiceLoader.load(classType, Thread.currentThread().getContextClassLoader());
// 根据服务定义的协议,依次暴露,如果有多个协议那就暴露多次
for (Object s : services) {
System.out.println("服务定义的协议匹配:" + s.getClass().getSimpleName());
if (serviceName.equals(s.getClass().getSimpleName())) {
return s;
}
}
return null;
}
}