-
ExtensionLoad中存在ExtensionLoaders缓存,缓存不同加载类型所对应的ExtensionLoad。当缓存没有命中时会去以同样的方式去加载ExtensionFactory,并将ExtensinoFactory加入缓存。之后通过getAdaptiveExtension来加载ExtenionFactory的接口实现类,并将其加入缓存。在getAdaptiveExtension中存在cacheAdaptiveInstance缓存,用来存放相应类型的自适应拓展类的实例。如果刚开始缓存没有命中就会去创建自适应拓展(createAdaptiveExtension)。创建自适应推展中包含3个步骤
(1)获取自适应拓展的Class
(2)利用反射进行实例化
(3)对实例进行参数注入。
其中获取自适应拓展Class(getAdaptiveExtensionClass)中,先获取所有的拓展类(getExtensionClasses),其中先去检查缓存cachedClassed(类名和class的映射),缓存没有命中就去加载拓展(loadExtensionClasses),其中先检查相应加载类型是否标注了SPI的注解,如果存在就获取SPI注解中的值。之后就会去加载解析三个路径下的配置文件(META-INF/dubbo、META/services、META-INF/dubbo/internal),之后就是通过将解析的key-valu存放到extensionClass中(key:name,value:Class),最后会将extensionClass赋值给cachedClasses。这样通过getExtensionClasses我们就可以得到一个cachedClasses。回到主题,目前我们加载的ExtensionFacoty,并通过解析配置文件得到具体的Class,其中包含了AdaptiveExtensionFactory,SpiExtensionFactory。AdaptiveExtensionFactory,该类标注了Adaptive注解,那么它会被直接缓存到cacheAdaptiveClass中。SpiExtensionFactory是一个普通的Class。这样我们就又回到了CreateAdaptiveExtension中,我们将得到的具体的cacheAdaptiveClass进行实例化。实例化之后进行参数注入。参数注入过程也很简单。先检查缓存(objectFactory就是ExtensinoFactory),刚开始是加载AdaptiveExtensinoFactory所以是null,直接返回。这样的话我们就获得了AdaptiveExtensinoFactory的实例并将其缓存到cachedAdaptiveInstance中。 -
至此我们总结一下:我们在创建具体类型的ExtensionLoad的过程中先创建了一个ExtensionFactoty类型的ExtensionLoad,并利用该ExtenbsionLoad创建了AdaptiveExtensionFactory并设置到objectFactory缓存中,最后将ExtensionFactory放入ExtensionLoad缓存中。至此在总结一下:我们创建的ExtensionLoad中包含了
(1)Extension_Load缓存,它缓存了具体类型和相应类型的ExtensionLoader。
(2)Extension_Instances缓存,它缓存了SpiExtensinoFactory和他的实例。 -
现在我们就得到了相应类型的ExtensionLoader。利用该Extension调用getAdaptiveExtension。这里需要注意下和加载ExtensionFactiry所不同之处在于创建自适应拓展类。
(1)构建自适应拓展代码
(2)编译代码生成class。 -
以下就是通过arthas反编译的自适应扩展代码。我们可以看到,本质就是通过通过URL,加载相应的具体拓展,并用具体的拓展调用相应的方法。不过需要注意的是,没有标注spi的方法会报UnsupportedOperationException异常。此外目标类型的参数注入:遍历目标类的所有方法,检测方法是否以 set 开头,且方法仅有一个参数,且方法访问级别为 public。从 ObjectFactory 中获取依赖对象,objectFactory 变量的类型为 AdaptiveExtensionFactory,AdaptiveExtensionFactory 内部维护了一个 ExtensionFactory 列表,用于存储其他类型的 ExtensionFactory。Dubbo 目前提供了两种 ExtensionFactory,分别是 SpiExtensionFactory 和 SpringExtensionFactory。前者用于创建自适应的拓展,后者是用于从 Spring 的 IOC 容器中获取所需的拓展。
/**
* Simple extension, has no wrapper
*/
@SPI("impl1")
public interface SimpleExt {
// @Adaptive example, do not specify a explicit key.
@Adaptive
String echo(URL url, String s);
@Adaptive({"key1", "key2"})
String yell(URL url, String s);
// no @Adaptive
String bang(URL url, int i);
}
package com.alibaba.dubbo.common.extensionloader.ext1;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
import com.alibaba.dubbo.common.extensionloader.ext1.SimpleExt;
public class SimpleExt$Adaptive implements SimpleExt {
public String echo(URL uRL, String string) {
if (uRL == null) {
throw new IllegalArgumentException("url == null");
}
URL uRL2 = uRL;
String string2 = uRL2.getParameter("simple.ext", "impl1");
if (string2 == null) {
throw new IllegalStateException(new StringBuffer().append("Fail to get extension(com.alibaba.dubbo.common.extensionloader.ext1.SimpleExt) name from url(").append(uRL2.toString()).append(") use keys([simple.ext])").toString());
}
SimpleExt simpleExt = (SimpleExt)ExtensionLoader.getExtensionLoader(SimpleExt.class).getExtension(string2);
return simpleExt.echo(uRL, string);
}
public String yell(URL uRL, String string) {
if (uRL == null) {
throw new IllegalArgumentException("url == null");
}
URL uRL2 = uRL;
String string2 = uRL2.getParameter("key1", uRL2.getParameter("key2", "impl1"));
if (string2 == null) {
throw new IllegalStateException(new StringBuffer().append("Fail to get extension(com.alibaba.dubbo.common.extensionloader.ext1.SimpleExt) name from url(").append(uRL2.toString()).append(") use keys([key1, key2])").toString());
}
SimpleExt simpleExt = (SimpleExt)ExtensionLoader.getExtensionLoader(SimpleExt.class).getExtension(string2);
return simpleExt.yell(uRL, string);
}
public String bang(URL uRL, int n) {
throw new UnsupportedOperationException("method public abstract java.lang.String com.alibaba.dubbo.common.extensionloader.ext1.SimpleExt.bang(com.alibaba.dubbo.common.URL,int) of interface com.alibaba.dubbo.common.extensionloader.ext1.SimpleExt is not adaptive method!");
}
}