dubbo中使用spi除了配置文件外还需要有@SPI和@Adaptive注解,这两个注解中都可以设置参数,且@Adaptive注解可以设置在方法上也可以设置在类上。下面我们来卡一下他的具体使用规则。
1、引入dubbo依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.x</version>
</dependency>
2、创建接口、实现类、配置文件:
@SPI("impl1")
public interface SpiService {
@Adaptive
String spiTest1(URL url);
String spiTest2(URL url);
}
实现类3个:
public class SpiServiceImpl1 implements SpiService {
@Override
public String spiTest1(URL url) {
return " SpiServiceImpl1 --> test1";
}
@Override
public String spiTest2(URL url) {
return " SpiServiceImpl1 --> test2";
}
}
public class SpiServiceImpl2 implements SpiService {
@Override
public String spiTest1(URL url) {
return " SpiServiceImpl2 --> test1";
}
@Override
public String spiTest2(URL url) {
return " SpiServiceImpl2 --> test2";
}
}
public class SpiServiceImpl3 implements SpiService {
@Override
public String spiTest1(URL url) {
return " SpiServiceImpl3 --> test1";
}
@Override
public String spiTest2(URL url) {
return " SpiServiceImpl3 --> test2";
}
}
3、配置文件:META-INF/dubbo/internal/cn.zsm.dubbo.service.SpiService
配置文件的路径可以有三种: META-INF/dubbo/internal 、 META-INF/dubbo 、META-INF/services
impl1=cn.zsm.dubbo.dubboprovider.service.impl.SpiServiceImpl1
impl2=cn.zsm.dubbo.dubboprovider.service.impl.SpiServiceImpl2
impl3=cn.zsm.dubbo.dubboprovider.service.impl.SpiServiceImpl3
4、编写测试类
@Test
void test1() {
ExtensionLoader<SpiService> extensionLoader = ExtensionLoader.getExtensionLoader(SpiService.class);
SpiService adaptiveExtension = extensionLoader.getAdaptiveExtension();
URL url = URL.valueOf("test://localhost/test");
System.out.println(adaptiveExtension.spiTest1(url));
}
输出: 调用impl1
这里我们是使用了@SPI注解中的默认的扩展点 "impl1", 下面我们不改变业务代码,在测试类中的URL参数中指定扩展点:
5、URL指定扩展点:
@Test
void test1() {
ExtensionLoader<SpiService> extensionLoader = ExtensionLoader.getExtensionLoader(SpiService.class);
SpiService adaptiveExtension = extensionLoader.getAdaptiveExtension();
// url中指定扩展点
URL url = URL.valueOf("test://localhost/test?cn.zsm.dubbo.service.SpiService=impl2");
System.out.println(adaptiveExtension.spiTest1(url));
}
执行结果: 调用impl2
6、不改变其他条件, 在SpiServiceImpl3 类上添加注解: @Adaptive
输出结果: 调用impl3
7、不改变其他条件,在SpiService 接口的 spiTest1方法的@Adaptive注解中添加属性值:
输出结果: 调用impl3
8、去掉impl3的@Adaptive注解
输出结果:调用impl1
9、如果我们在SpiService 接口中,让@Adaptive的值与@SPI的值不同:
输出结果: 调用impl1
10、错误示范, spiTest2 上没有@Adaptive注解,我们在测试类中调用它看会怎样:
输出结果:
public java.lang.String spiTest2(com.alibaba.dubbo.common.URL arg0)
{
throw new UnsupportedOperationException("method public abstract java.lang.String
cn.zsm.dubbo.service.SpiService.spiTest2(com.alibaba.dubbo.common.URL) of interface
cn.zsm.dubbo.service.SpiService is not adaptive method!");
}
前面爆出一段错误,spiTest2 is not adaptive method , 输出依然是test1。 可以看出没有@Adaptive注解的方法不能被扩展。
综合上面几个例子可以看出:
- dubbo要使用SPI扩展,被扩展的接口必须要@SPI注解, 方法必须有@Adaptive注解
- 扩展类的优先级: @Adaptive标记的扩展类 > URL中指定的扩展类 > @SPI 注解中指定的扩展类
- 如果@SPI注解指定了扩展类, 方法的@Adaptive注解中也指定了扩展类,@SPI中指定的扩展类会覆盖URL中指定的扩展类; 且@Adaptive 与@SPI指定的扩展类不同时,会使用@SPI中指定的扩展类