Dubbo SPI扩展点(一)

Dubbo扩展点加载的功能

Dubbo的扩展点加载机制类似于Java的SPI,我们知道Java的SPI在使用的时候,只能通过遍历来进行实现的查找和实例化,有可能会一次性把所有的实现都实例化,这样会造成有些不使用的扩展实现也会被实例化,这就会造成一定的资源浪费。有关Dubbo的改进,参照文档上的说明:

  • JDK标准的SPI会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源。
  • 如果扩展点加载失败,连扩展点的名称都拿不到了。比如:JDK标准的ScriptEngine,通过getName();获取脚本类型的名称,但如果RubyScriptEngine因为所依赖的jruby.jar不存在,导致RubyScriptEngine类加载失败,这个失败原因被吃掉了,和ruby对应不起来,当用户执行ruby脚本时,会报不支持ruby,而不是真正失败的原因。
  • 增加了对扩展点IoC和AOP的支持,一个扩展点可以直接setter注入其它扩展点。

Dubbo扩展点的特征

  • @SPI注解,被此注解标记的接口,就表示是一个可扩展的接口。

  • @Adaptive注解,有两种注解方式:一种是注解在类上,一种是注解在方法上。

    • 注解在类上,而且是注解在实现类上,目前dubbo只有AdaptiveCompiler和AdaptiveExtensionFactory类上标注了此注解,这是些特殊的类,ExtensionLoader需要依赖他们工作,所以得使用此方式。
    • 注解在方法上,注解在接口的方法上,除了上面两个类之外,所有的都是注解在方法上。ExtensionLoader根据接口定义动态的生成适配器代码,并实例化这个生成的动态类。被Adaptive注解的方法会生成具体的方法实现。
      没有注解的方法生成的实现都是抛不支持的操作异常UnsupportedOperationException。被注解的方法在生成的动态类中,会根据url里的参数信息,来决定实际调用哪个扩展。

例如:

@SPI(RandomLoadBalance.NAME)
public interface LoadBalance {

    @Adaptive("loadbalance")
    <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;

}

dubbo实现SPI

在 Dubbo 中,想要拓展拓展点,只需要以下几个步骤

1.创建拓展点实现类 (以LoadBalance为例):

public class MyLoadBalance extends AbstractLoadBalance {
    @Override
    protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
        return null;
    }
}

2.在指定文件夹下创建以拓展点全路径名(org.apache.dubbo.rpc.cluster.LoadBalance)的文件,Dubbo 中有多个目录都可以配置拓展点,这里用在resource/META-INF/dubbo/org.apache.dubbo.rpc.cluster.LoadBalance

myLoadBalance=com.demo.loadbalance.MyLoadBalance

3.测试

public class TestLoadBalance {
    public static void main(String[] args) {
        LoadBalance loadBalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension("myLoadBalance");
        System.out.println(loadBalance);
    }
}

可以发现我们已经可以拿到我们自己的实现类了。

那么他具体是怎么实现的呢?让我们继续往下看 Dubbo SPI扩展点(二)

原文地址:https://www.cnblogs.com/snail-gao/p/14166158.html