【dubbo源码】6.dubbo的spi机制

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/接口全限定名,内容为配置名=扩展实现类全限定名,多个实现类用换行符分隔。

image

Dubbo的加载拓展类Api : ExtensionLoader

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

比如ServiceConfig :

image

使用示例 :

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());
    }
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容