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()
- getExtensionClasses()–>
- getAdaptiveExtensionClass()–>
- createAdaptiveExtension()–>
- 代码获取自适应扩展类
Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
此为获取protocol的自适应扩展类
- 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;
}
- 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);
}
}
- getAdaptiveExtensionClass获取自适应扩展类文件
private Class<?> getAdaptiveExtensionClass() {
getExtensionClasses(); //加载指定路径下的文件
//cachedAdaptvieClass, @Adaptive这个表示在类上的
//如果缓存中已经找到自适应类的话直接返回,意思也就是这个spi有Adaptive的注解类
//比如:当前获取的自适应实现类是AdaptiveExtensionFactory或者是AdaptiveCompiler,就直接返回,这两个类是特殊用处的,不用代码生成,而是现成的代码
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
//否则在方法级别上,反射代理生成类
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
- 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;
}
- 生成代理类的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);
}
}