【dubbo源码】6.dubbo的spi机制
2021-07-03 本文已影响0人
天还下着毛毛雨
Dubbo的SPI由JDK标准的SPI加强而来
Dubbo 改进了 JDK 标准的 SPI 的以下问题:
- JDK 标准的 SPI 会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源。
- 如果扩展点加载失败,连扩展点的名称都拿不到了。比如:JDK 标准的 ScriptEngine,通过 getName() 获取脚本类型的名称,但如果 RubyScriptEngine 因为所依赖的 jruby.jar 不存在,导致 RubyScriptEngine 类加载失败,这个失败原因被吃掉了,和 ruby 对应不起来,当用户执行 ruby 脚本时,会报不支持 ruby,而不是真正失败的原因。
- 增加了对扩展点 IoC 和 AOP 的支持,一个扩展点可以直接 setter 注入其它扩展点。
约定方式:
在jar包内,放置SPI配置文件 META-INF/dubbo/接口全限定名,内容为配置名=扩展实现类全限定名,多个实现类用换行符分隔。

Dubbo的加载拓展类Api : ExtensionLoader
Dubbo提供了对Spi配置类的加载api,在源码中也是使用这种Api来获取指定的拓展类实例
比如ServiceConfig :

使用示例 :
api接口 :
AdaptiveApi :
@SPI("spring")
public interface AdaptiveApi {
void doSomething();
}
多个实现类 :
@Activate(value = "mybatis1",group = "mybatis")
public class Mybatis1Adaptive implements AdaptiveApi {
@Override
public void doSomething() {
System.out.println("mybatis1");
}
}
@Activate(value = "mybatis",group = "mybatis")
public class MybatisAdaptive implements AdaptiveApi {
@Override
public void doSomething() {
System.out.println("mybatis");
}
}
@Adaptive
@Activate(value = "rabbit", group = "rabbit")
public class RabbitAdaptive implements AdaptiveApi {
@Override
public void doSomething() {
System.out.println("rabbit");
}
}
@Activate(value = "spring",group = "spring")
public class SpringAdaptive implements AdaptiveApi {
@Override
public void doSomething() {
System.out.println("spring");
}
}
spi配置文件:
META-INF/dubbo/com.lb.dubbo_api.dubbo_spi.AdaptiveApi
spring=com.lb.dubbo_api.dubbo_spi.SpringAdaptive
rabbit=com.lb.dubbo_api.dubbo_spi.RabbitAdaptive
mybatis=com.lb.dubbo_api.dubbo_spi.MybatisAdaptive
mybati1=com.lb.dubbo_api.dubbo_spi.Mybatis1Adaptive
测试api :
public class SpiTest {
@Test
public void testSpi() {
// 获取默认的类型实例 接口上@SPI("spring")指定的key,到com.lb.dubbo_api.dubbo_spi.AdaptiveApi文件里去对应的类型
AdaptiveApi defaultExtension = ExtensionLoader.getExtensionLoader(AdaptiveApi.class).getDefaultExtension();
System.out.println(defaultExtension);
// 获取AdaptiveApi实现类中带有@Adaptive注解的类,超出一个则报错 More than 1 adaptive class found: java.lang.Class, java.lang.Class
AdaptiveApi adaptiveExtension = ExtensionLoader.getExtensionLoader(AdaptiveApi.class).getAdaptiveExtension();
adaptiveExtension.doSomething();
// 获取配置文件中所有的key,除了@Adaptive注解
Set<String> supportedExtensions = ExtensionLoader.getExtensionLoader(AdaptiveApi.class).getSupportedExtensions();
for (String loadedExtension : supportedExtensions) {
System.out.println(loadedExtension);
}
// 获取接口上@SPI("spring")指定的key
Set<String> loadedExtensions = ExtensionLoader.getExtensionLoader(AdaptiveApi.class).getLoadedExtensions();
for (String loadedExtension : loadedExtensions) {
System.out.println(loadedExtension);
}
// 获取已加载的实现类的实例,只有接口上@SPI("spring")配置的这个才可以获取到
AdaptiveApi spring = ExtensionLoader.getExtensionLoader(AdaptiveApi.class).getLoadedExtension("spring");
spring.doSomething();
// 获取group为mybatis的类,如果实现类上@Activate配置了value属性,则会根据url的key与value进行匹配,匹配到的才会返回
// 如果group为mybatis的类的@Activate都没有配置,就会全部返回
URL url = URL.valueOf("test://localhost:8081");
List<AdaptiveApi> mybatis = ExtensionLoader.getExtensionLoader(AdaptiveApi.class).getActivateExtension(url, new String[]{}, "mybatis");
System.out.println(mybatis.size());
// 获取group为mybatis的类,如果实现类上@Activate配置了value属性,则会根据url的param与value进行匹配,匹配到的才会返回
// 先分组匹配,再url匹配
URL url1 = URL.valueOf("test://localhost:8081");
URL url2 = url1.addParameter("mybatis2", "...");
List<AdaptiveApi> mybatis1 = ExtensionLoader.getExtensionLoader(AdaptiveApi.class).getActivateExtension(url2, new String[]{}, "mybatis");
System.out.println(mybatis1.size());
// 获取group为mybatis的类,如果实现类上@Activate配置了value属性,则会根据url的param与value进行匹配,匹配到的才会返回
// 先分组匹配,再url匹配,才会返回getActivateExtension的第二个字符串数组参数指定的key的类型实例
URL url3 = URL.valueOf("test://localhost:8081").addParameter("mybatis2", "...");
List<AdaptiveApi> springs = ExtensionLoader.getExtensionLoader(AdaptiveApi.class).getActivateExtension(url3, new String[]{"spring"}, "mybatis");
System.out.println(springs.size());
}
}