SPI
SPI的全程是Service Provider Interface。是Java提供的一套用来被第三方实现或者扩展的接口,它可以用来启用框架扩展和替换组件。 SPI的作用就是为这些被扩展的API寻找服务实现。
####Java SPI
Java SPI使用了策略模式。一个接口多种实现。我们只声明接口,具体的实现不在程序中明确指定,而是由程序外的配置掌控,用于指定具体实现的配置。具体步骤如下:
a). 定义一个接口
b).编写这个接口的实现类
c).在META-INF/services/目录下创建一个以接口全路径命名的文件。
d).文件内容为具体实现类的全路径名。如有多个,换行书写
e).在代码中通过 java.util.ServiceLoader来加载具体的实现类
代码如下:
接口
public interface PrintInfoService {
void printInfo();
}
接口实现类 这里做两个实现类
public class PrintInfo2ServiceImpl implements PrintInfoService {
@Override
public void printInfo() {
System.out.println("hello,java SPI PrintInfo2ServiceImpl ");
}
}
import java.util.ServiceLoader;
public class PrintInfoServiceImpl implements PrintInfoService {
@Override
public void printInfo() {
System.out.println("hello,java SPI PrintInfoDubboServiceImpl");
}
public static void main(String[] args) {
ServiceLoader<PrintInfoService> load = ServiceLoader.load(PrintInfoService.class);
for (PrintInfoService printInfoService : load) {
printInfoService.printInfo();
}
}
}
serverice扩展文件
Dubbo SPI
下边我们来看dubbSPI是怎么实现的
需要实现的步骤是类似的:
a).定义一个接口
b).实现一个接口
c).在 MATE-INF/dobbo 下创建以接口全限定名的文件名
d).文件内容为 key=实现类全限定名 例如: impl=chenyi.dubbo.test.dubbo.PrintInfoDubboServiceImpl
e).接口添加注解SPI(“impl”)SPI:是dubbo包下的。 impl是配置文件中的key
f).通过dubbo的方式获取对应扩展类: ExtensionLoader.getExtensionLoader(PrintInfoDubboService.class)
.getDefaultExtension();
具体如下:
import com.alibaba.dubbo.common.extension.SPI;
@SPI("impl")
public interface PrintInfoDubboService {
void printInfo();
}
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class PrintInfoDubboServiceImpl implements PrintInfoDubboService {
@Override
public void printInfo() {
System.out.println("hello,dubbo SPI PrintInfoDubboServiceImpl");
}
public static void main(String[] args) {
PrintInfoDubboService defaultExtension = ExtensionLoader.getExtensionLoader(PrintInfoDubboService.class)
.getDefaultExtension();
defaultExtension.printInfo();
}
}
以上便是 使用JAVA SPI 和 Dubbo SPI的简单例子。
与JAVA SPI 相比,dubbo SPI做了一定的改进和优化。
- JDK标准的SPI会一次性实例化扩展节点所有实现类,如果扩展实现没有用上也加载,就会浪费资源。dubbo则是在文件中配置的才会被加载
- 如果扩展加载失败,无法获取到具体的失败原因。 dubbo在扩展加载失败的时候会先抛出真实异常,并打印日志。扩展点在被动加载的时候,即使有部分扩展加载失败也不会影响其他扩展点和整个框架的使用。
- dubbo SPI 自己实现了IOC和AOP机制,一个扩展点可以通过Setter方法注入。dubbo支持包装扩展类,推荐把通用的抽象逻辑放到包装类里。
####扩展点的配置规范
Dubbo SPI 和Java SPI类似 需要在META-INF/dubbo下放置对应的SPI配置文件。
- 文件名称需要命名为借口的全限定名。
- 配置文件内容为Key=接口实现类的全限定名。如果有多个则使用换行符分隔。其中Key会通过dubbo SPI注解中的传入参数。
- 文件配置路径。 在dubbo启动时,会默认扫描 META-INF/services/ META-INF/dubbo/ META-INF/dubbo/internal