这个功能的主要实现类是采用了工厂模式的ExtensionLoader。还有一些属性用来保存解析过程当中的结果。比如每个class对应的扩展加载器,
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();
对应的实例对象 private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>();等等
2.在dubbo里随处可见的代码是ExtensionLoader.getExtensionLoader(这里是接口).getAdaptiveExtension(),根据它可以获取这个接口的自适应实现类。这个也就是这个扩展机制
起作用的入口。先判断是不是又SPI注解并且是不是接口类型,然后就是查看缓存。
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
if (loader == null) {
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}
3.初始化new ExtensionLoader<T>(type)时,会把接口类型传进去,这里会判断参数的类型,如果是ExtensionFactory就会直接返回,否则就会开始加载ExtensionFactory并且获取
它的自适应扩展。来充当这个接口类型的对象工厂属性,为以后能从objectFactory 里面获取想要的属性,并且进行set注入到返回的具体对象里。
private ExtensionLoader(Class<?> type) {
this.type = type;
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
4.当ExtensionFactory接口类型作为参数再次走到这个流程的时候就会执行直接返回上层执行函数,并直接执行getAdaptiveExtension()方法,获取自适应扩展返回值给最初的objectFactory 赋值,常见的查看缓存以及二段检查锁如果不存在就会开始创建该类型ExtensionFactory的自适应扩展,
public T getAdaptiveExtension() {
Object instance = cachedAdaptiveInstance.get();
if (instance == null) {
if(createAdaptiveInstanceError == null) {
synchronized (cachedAdaptiveInstance) {
instance = cachedAdaptiveInstance.get();
if (instance == null) {
instance = createAdaptiveExtension();
cachedAdaptiveInstance.set(instance);
}
}
}
}
return (T) instance;
}
开始创建,获取class类型,生成实例并且注入对应的需要set的属性
private T createAdaptiveExtension() {
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
}
获取自适应扩展class以待实例化
private Class<?> getAdaptiveExtensionClass() {
getExtensionClasses();
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
首先获取扩展的全部class信息,不管是自适应还是默认激活等等,这个cachedClasses存储的就是最初的那些文件配置的键值对,里面不包括自适应扩展键值对
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;
}
5.开始加载文件里面的扩展,首先检查这个接口类型上有没有设置默认值,也就是形如@SPI("javassist")
// 此方法已经getExtensionClasses方法同步过。
private Map<String, Class<?>> loadExtensionClasses() {
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if(defaultAnnotation != null) {
String value = defaultAnnotation.value();
if(value != null && (value = value.trim()).length() > 0) {
String[] names = NAME_SEPARATOR.split(value);
if(names.length > 1) {
throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
+ ": " + Arrays.toString(names));
}
if(names.length == 1) cachedDefaultName = names[0];
}
}
Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
loadFile(extensionClasses, DUBBO_DIRECTORY);
loadFile(extensionClasses, SERVICES_DIRECTORY);
return extensionClasses;
}
具体加载文件的扩展,并且获取自适应扩展,具体就是每获取文件的一行就会解析出来一个键值对,判断这个class有没有Adaptive注解,有的话就是这个接口的自适应扩展,缓存起来cachedAdaptiveClass ,如果没有的话,就会判断这个类是不是Wrapper类型的class判断方式也就是这种类型的类都有一个构造函数是以这个类型为参数的,然后缓存起来cachedWrapperClasses,这个类型在以后的处理中有大用途,不可忽视,然后就是存储cachedActivates带有Activate注解的class,最后在顺带缓存上class与name的值键对cachedNames,最后返回键值对extensionClasses,最后缓存在Holder<Map<String, Class<?>>> cachedClasses 。
if (line.length() > 0) {
Class<?> clazz = Class.forName(line, true, classLoader);
if (clazz.isAnnotationPresent(Adaptive.class)) {
if(cachedAdaptiveClass == null) {
cachedAdaptiveClass = clazz;
}
} else {
try {
clazz.getConstructor(type);
Set<Class<?>> wrappers = cachedWrapperClasses;
if (wrappers == null) {
cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
wrappers = cachedWrapperClasses;
}
wrappers.add(clazz);
} catch (NoSuchMethodException e) {
clazz.getConstructor();
if (name == null || name.length() == 0) {
name = findAnnotationName(clazz);
if (name == null || name.length() == 0) {
if (clazz.getSimpleName().length() > type.getSimpleName().length()
&& clazz.getSimpleName().endsWith(type.getSimpleName())) {
name = clazz.getSimpleName().substring(0, clazz.getSimpleName().length() - type.getSimpleName().length()).toLowerCase();
} else {
throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + url);
}
}
}
String[] names = NAME_SEPARATOR.split(name);
if (names != null && names.length > 0) {
Activate activate = clazz.getAnnotation(Activate.class);
if (activate != null) {
cachedActivates.put(names[0], activate);
}
for (String n : names) {
if (! cachedNames.containsKey(clazz)) {
cachedNames.put(clazz, n);
}
Class<?> c = extensionClasses.get(n);
if (c == null) {
extensionClasses.put(n, clazz);
} else if (c != clazz) {
throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName());
}
}
}
}
}
}
6.现在就是加载完该接口所包含的所有扩展,然后获取或者创建,之前如果有自适应扩展的话cachedAdaptiveClass就应该会有值,但是如果没有的话就需要用相应的jdk或者Javassist根据字符串动态生成class。如果接口类是ExtensionFactory的话,到这里就会直接返回,因为它已经有了自适应扩展AdaptiveExtensionFactory,针对没有的情况
private Class<?> createAdaptiveExtensionClass() {
String code = createAdaptiveExtensionClassCode();
ClassLoader classLoader = findClassLoader();
com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
return compiler.compile(code, classLoader);
}
生成具体的类字符串code信息createAdaptiveExtensionClassCode(),具体意思是,首先这个接口的方法中必须至少有一个方法有Adaptive
注解,然后在生成源码时,对于没有这个注解的方法抛出不支持异常,生成的这个class的类名为Protocol$Adpative这种形式,也就是这个接口的一个实现类,只不过这个自适应扩展类生成的具体类会随着参数的变化而变化,主要的具体参数就是URL这个在dubbo中很重要的类,他会根据一些具体的规则
String defaultExtName = cachedDefaultName;这个就是spi注解带的那个默认值,
getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName);
getNameCode = String.format("url.getParameter(\"%s\", \"%s\")", value[i], defaultExtName);
getNameCode = String.format("( url.getProtocol() == null ? \"%s\" : url.getProtocol() )", defaultExtName);
code.append("\nString extName = ").append(getNameCode).append(";");
s = String.format("\n%s extension = (%<s)%s.getExtensionLoader(%s.class).getExtension(extName);",
type.getName(), ExtensionLoader.class.getSimpleName(), type.getName());
最后根据这个值重新从这个工厂中获取对应的对象,所以这个getNameCode的获取是一个很重要的操作。
7.源代码生成之后就需要获取适合的class生成工具生成具体class,这个时候就会重新走之前的逻辑ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension(),这个Compiler具有对应的自适应扩展AdaptiveCompiler
都获取到自适应扩展之后就会进行实例化然后注入该有的属性,这个时候ExtensionFactory接口的自适应扩展的objectFactory 为null,所以这些对于他可以忽略,但是针对其他接口,objectFactory 属性就是AdaptiveExtensionFactory,这是在初始化函数里面赋值得,在初始化AdaptiveExtensionFactory时会把另外两个SpringExtensionFactory和SpiExtensionFactory放入List<ExtensionFactory> factories属性以供后来其他的set属性注入时从具体容器里面获取需要的对象。下面就是检查有没有需要set属性的方法,有的话就会从上面那两个容器里获取对象进行反射调用赋值。至此,一个完整的自适应扩展已经生成并且缓存在cachedAdaptiveInstance
private T injectExtension(T instance) {
try {
if (objectFactory != null) {
for (Method method : instance.getClass().getMethods()) {
if (method.getName().startsWith("set")
&& method.getParameterTypes().length == 1
&& Modifier.isPublic(method.getModifiers())) {
Class<?> pt = method.getParameterTypes()[0];
try {
String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
Object object = objectFactory.getExtension(pt, property);
if (object != null) {
method.invoke(instance, object);
}
}
}
}
}
}
return instance;
}
8.下来就是一些类似ExtensionLoader.getExtensionLoader(type).getExtension(name);这种返回指定名字的扩展。
public T getExtension(String name) {
Holder<Object> holder = cachedInstances.get(name);
if (holder == null) {
cachedInstances.putIfAbsent(name, new Holder<Object>());
holder = cachedInstances.get(name);
}
Object instance = holder.get();
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
instance = createExtension(name);
holder.set(instance);
}
}
}
return (T) instance;
}
开始创建对应名字的扩展,我们熟悉的加载扩展方法getExtensionClasses,获取到指定名字的class之后查看有没有已经在缓存中的实例,然后就是注入set属性,继续就是很重要的一步,检查缓存中是否有包裹类型的class,然后进行wrapper包裹后返回最终实例,缓存在ConcurrentMap<String, Holder<Object>> cachedInstances
private T createExtension(String name) {
Class<?> clazz = getExtensionClasses().get(name);
try {
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
injectExtension(instance);
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && wrapperClasses.size() > 0) {
for (Class<?> wrapperClass : wrapperClasses) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
return instance;
}
}
9.这里附上Protocol接口当初生成的自适应扩展以供参考
package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol {
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!");
}
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);
}
}