Dubbo-SPI

Dubbo-SPI

SPI是一种服务发现机制。

dubbo的spi实现原理和java spi相似,只不过增强了一些功能和优化。java spi的是把所有的spi都加载到内存,但对于dubbo来说可能只需要加载用户指定的实现方式,而不需要全部加载进来,全部加载也会有性能问题,所以dubbo实现的是在有用到的时候去加载这些扩展组件。

SPI机制有几个重要的注解:

1、@SPI注解,被此注解标记的接口,就表示是一个可扩展的接口,并标注默认值。
2、@Adaptive注解,有两种注解方式:一种是注解在类上,一种是注解在方法上。Adaptive 自适应扩展点
3、@Activate注解,此注解需要注解在类上或者方法上,并注明被激活的条件,以及所有的被激活实现类中的排序信息

@Adptive自适应扩展点

什么叫自适应扩展点呢?我们先演示一个例子,在下面这个例子中,我们传入一个 Compiler 接口,它会返回一个 AdaptiveCompiler。这个就叫自适应。

Compiler compiler=ExtensionLoader.getExtensionLoader(Compiler.class).getAdaptiveExtension(); System.out.println(compiler.getClass());
它是怎么实现的呢? 我们根据返回的 AdaptiveCompiler 这个类,看到这个类上面有一个注解@Adaptive。 这个就是一个自适应 扩展点的标识。它可以修饰在类上,也可以修饰在方法上面。这两者有什么区别呢? 简单来说,放在类上,说明当前类是一个确定的自适应扩展点的类。如果是放在方法级别,那么需要生成一个动态字节码,来进行转发。
比如拿 Protocol 这个接口来说,它里面定义了 export 和 refer 两个抽象方法,这两个方法分别带有@Adaptive 的标识,标识是一个自适应方法。
我们知道 Protocol 是一个通信协议的接口,具体有多种实现,那么这个时候选择哪一种呢? 取决于我们在使用 dubbo 的时候所 配置的协议名称。而这里的方法层面的 Adaptive 就决定了当前这个方法会采用何种协议来发布服务。

如何获取自适应扩展类

  • getAdaptiveExtension()–>
    • createAdaptiveExtension()–>
      • getAdaptiveExtensionClass()–>
        • getExtensionClasses()–>
          • loadExtensionClasses()
  1. 代码获取自适应扩展类
Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

此为获取protocol的自适应扩展类

  1. getAdaptiveExtension()方法
public T getAdaptiveExtension() {
  //先从缓存中获取
  Object instance = cachedAdaptiveInstance.get();
  //双重校验锁
  if (instance == null) {
    if (createAdaptiveInstanceError == null) {
      synchronized (cachedAdaptiveInstance) {
        instance = cachedAdaptiveInstance.get();
        if (instance == null) {
          try {
            //创建自适应扩展
            instance = createAdaptiveExtension();
            //设置缓存
            cachedAdaptiveInstance.set(instance);
          } catch (Throwable t) {
            createAdaptiveInstanceError = t;
            throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
          }
        }
      }
    } else {
      throw new IllegalStateException("Failed to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
    }
  }

  return (T) instance;
}
  1. createAdaptiveExtension创建自适应扩展
private T createAdaptiveExtension() {
  try {
    //获得一个自适应扩展点的实例,通过反射实例化
    return injectExtension((T) getAdaptiveExtensionClass().newInstance());
  } catch (Exception e) {
    throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
  }
}
  1. getAdaptiveExtensionClass获取自适应扩展类文件
private Class<?> getAdaptiveExtensionClass() {
  getExtensionClasses(); //加载指定路径下的文件

  //cachedAdaptvieClass, @Adaptive这个表示在类上的
  //如果缓存中已经找到自适应类的话直接返回,意思也就是这个spi有Adaptive的注解类
  //比如:当前获取的自适应实现类是AdaptiveExtensionFactory或者是AdaptiveCompiler,就直接返回,这两个类是特殊用处的,不用代码生成,而是现成的代码
  if (cachedAdaptiveClass != null) {
    return cachedAdaptiveClass;
  }
  //否则在方法级别上,反射代理生成类
  return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
  1. getAdaptiveExtensionClass方法中调用的getExtensionClasses方法,扫描所有类信息到缓存。
private Map<String, Class<?>> getExtensionClasses() {
    Map<String, Class<?>> classes = cachedClasses.get();
    if (classes == null) {
        synchronized (cachedClasses) {
            classes = cachedClasses.get();
            if (classes == null) {
                classes = loadExtensionClasses();
                cachedClasses.set(classes);
            }
        }
    }
    return classes;
}
  1. 生成代理类的class文件
private Class<?> createAdaptiveExtensionClass() {
  //生成动态代理类的字符串
  String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
  ClassLoader classLoader = findClassLoader();
  //ClassLoader
  org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.
    getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).
    getAdaptiveExtension(); //Javasssit
  return compiler.compile(code, classLoader);
}

7.最终会生成一个如Protocol$Adpative这个自适应扩展类实力

import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol {
  public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws java.lang.Class {
    if (arg1 == null) throw new IllegalArgumentException("url == null");

    com.alibaba.dubbo.common.URL url = arg1;
    String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );

    if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
    
    com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
    
    return extension.refer(arg0, arg1);
  }
  
  public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.Invoker {
    if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
    
    if (arg0.getUrl() == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");com.alibaba.dubbo.common.URL url = arg0.getUrl();
    
    String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
    
    if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
    
    com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
    
    return extension.export(arg0);
  }
  
  public void destroy() {
  	throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
  }
  
  public int getDefaultPort() {
  	throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
  }
}

8如果@Adaptive是注解在类上,如直接使用这个类的实力。如Compiler的自适应扩展类AdaptiveCompiler

@Adaptive
public class AdaptiveCompiler implements Compiler {

    private static volatile String DEFAULT_COMPILER;

    public static void setDefaultCompiler(String compiler) {
        DEFAULT_COMPILER = compiler;
    }

    @Override
    public Class<?> compile(String code, ClassLoader classLoader) {
        Compiler compiler;
        ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);
        String name = DEFAULT_COMPILER; // copy reference
        if (name != null && name.length() > 0) { //
            compiler = loader.getExtension(name); //根据name进行加载
        } else {
            compiler = loader.getDefaultExtension(); //默认扩展点
        }
        return compiler.compile(code, classLoader);
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值