标签:dubbo
spi(service providerinterface),是DUBBO功能强大的保障。核心支持类ExtensionLoader。
具体分析可以参照<Dubbo原理解析-Dubbo内核实现之基于SPI思想Dubbo内核实现>.
1.比较重要的注解
@SPI:扩展点接口的标识 :作用域在类上;
@Adaptive:为生成Adaptive实例提供参数,作用域在类或方法上;
@Activate:可以被框架中自动激活加载扩展,此Annotation用于配置扩展被自动激活加载条件。
1.1 测试对象代码
#1.声明SPI 默认为imp1
@SPI("impl1")
public interface SimpleExt {
// 没有使用key的@Adaptive !
@Adaptive
String echo(URL url, String s);
@Adaptive({"key1", "key2"})
String yell(URL url, String s);
// 无@Adaptive !
String bang(URL url, int i);
}
//实现类1
public class SimpleExtImpl1 implements SimpleExt {
public String echo(URL url, String s) {
return "Ext1Impl1-echo";
}
public String yell(URL url, String s) {
return "Ext1Impl1-yell";
}
public String bang(URL url, int i) {
return "bang1";
}
}
//实现类2
public class SimpleExtImpl2 implements SimpleExt {
public String echo(URL url, String s) {
return "Ext1Impl2-echo";
}
public String yell(URL url, String s) {
return "Ext1Impl2-yell";
}
public String bang(URL url, int i) {
return "bang2";
}
}
//实现类3
public class SimpleExtImpl3 implements SimpleExt {
public String echo(URL url, String s) {
return "Ext1Impl3-echo";
}
public String yell(URL url, String s) {
return "Ext1Impl3-yell";
}
public String bang(URL url, int i) {
return "bang3";
}
}1.2 配置文件com.alibaba.dubbo.common.extensionloader.ext1.SimpleExt
位置要放在如下位置
private static final String SERVICES_DIRECTORY = "META-INF/services/"; private static final String DUBBO_DIRECTORY = "META-INF/dubbo/"; private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";
具体内容如下
# Comment 1 impl1=com.alibaba.dubbo.common.extensionloader.ext1.impl.SimpleExtImpl1#Hello World impl2=com.alibaba.dubbo.common.extensionloader.ext1.impl.SimpleExtImpl2 # Comment 2 impl3=com.alibaba.dubbo.common.extensionloader.ext1.impl.SimpleExtImpl3 # with head space
定义3个实现。
1.4 测试
@Test
public void test_getDefaultExtension() throws Exception {
SimpleExt ext = ExtensionLoader.getExtensionLoader(SimpleExt.class).getDefaultExtension();
assertThat(ext, instanceOf(SimpleExtImpl1.class));
String name = ExtensionLoader.getExtensionLoader(SimpleExt.class).getDefaultExtensionName();
assertEquals("impl1", name);
}由于@SPI("impl1"),定义了默认实现的名称为imp1.
@Test
public void test_getExtension() throws Exception {
assertTrue(ExtensionLoader.getExtensionLoader(SimpleExt.class).getExtension("impl1") instanceof SimpleExtImpl1);
assertTrue(ExtensionLoader.getExtensionLoader(SimpleExt.class).getExtension("impl2") instanceof SimpleExtImpl2);
}getExtensionLoader(Class<T> type):根据类名,返回具体实现类。这些配置信息在META对应文件中配置。当然,也可以使用@Extention注解配置(只不过,这个注解已经废弃了)
@Test
public void test_getAdaptiveExtension_defaultAdaptiveKey() throws Exception {
{
SimpleExt ext = ExtensionLoader.getExtensionLoader(SimpleExt.class).getAdaptiveExtension();
Map<String, String> map = new HashMap<String, String>();
//没有指定具体parameters参数,所以选用默认实现,最后返回impl1
URL url = new URL("p1", "1.2.3.4", 1010, "path1", map);
//如果不设置默认的SPI实现类,则报异常
//java.lang.IllegalStateException: Fail to get extension(com.alibaba.dubbo.common.extensionloader.ext1.SimpleExt) name from url(p1://1.2.3.4:1010/path1) use keys([simple.ext])
String echo = ext.echo(url, "haha");
assertEquals("Ext1Impl1-echo", echo);
}
{
SimpleExt ext = ExtensionLoader.getExtensionLoader(SimpleExt.class).getAdaptiveExtension();
Map<String, String> map = new HashMap<String, String>();
map.put("simple.ext", "impl2");//手动在参数中配置impl2,参数为simple.ext
URL url = new URL("p1", "1.2.3.4", 1010, "path1", map);
String echo = ext.echo(url, "haha");
assertEquals("Ext1Impl2-echo", echo);
}
}@Adaptive 测试
由于 yell方法声明了,@Adaptive({"key1", "key2"})
@Test
public void test_getAdaptiveExtension_customizeAdaptiveKey() throws Exception {
SimpleExt ext = ExtensionLoader.getExtensionLoader(SimpleExt.class).getAdaptiveExtension();
Map<String, String> map = new HashMap<String, String>();
map.put("key2", "impl2");
URL url = new URL("p1", "1.2.3.4", 1010, "path1", map);
String echo = ext.yell(url, "haha");
assertEquals("Ext1Impl2-yell", echo);
url = url.addParameter("key1", "impl3"); // 注意: URL是值类型
echo = ext.yell(url, "haha");
assertEquals("Ext1Impl3-yell", echo);
}如果参数不是key1,key2,即使参数值输入impl1,impl2也是无意义的。
由于bang方法,没有被@Adaptive 修饰,所以以下代码,会报异常
ExtensionLoader.getExtensionLoader(SimpleExt.class).getAdaptiveExtension().bang(..);
of interface com.alibaba.dubbo.common.extensionloader.ext1.SimpleExt is not adaptive method!
以上内容,是通过代码演练的方式,讲解了dubbo SPI机制的威力。
如果对底层实现感兴趣,可参看博客。
参照:Dubbo原理解析-Dubbo内核实现之基于SPI思想Dubbo内核实现
本文出自 “简单” 博客,请务必保留此出处http://dba10g.blog.51cto.com/764602/1880962
标签:dubbo
原文地址:http://dba10g.blog.51cto.com/764602/1880962