Adaptive
getAdaptiveExtension
通过这个方法得到某个接口的适配实例。
@SuppressWarnings("unchecked")
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("fail to create adaptive instance: " + t.toString(), t);
}
}
}
} else {
throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
}
}
return (T) instance;
}
createAdaptiveExtension
该方法创建适配扩展实例,getAdaptiveExtensionClass
显然会得到适配扩展的类,然后通过无参构造方法得到实例对象。
@SuppressWarnings("unchecked")
private T createAdaptiveExtension() {
try {
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
}
}
getAdaptiveExtensionClass
得到适配扩展的类,当然首先就是要通过spi机制尝试加载一下,如果加载过程中存在Adaptive
注解的类,那么就直接返回,如果并没有,那么dubbo就会生成源码去实现。
private Class> getAdaptiveExtensionClass() {
getExtensionClasses();
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
createAdaptiveExtensionClass
编译得到适配扩展类,注意此处需要得到适配编译类,有上个方法可知Compiler
接口肯定已经存在了Adaptive
注解的适配扩展。
private Class> createAdaptiveExtensionClass() {
//生成源码
String code = createAdaptiveExtensionClassCode();
//得到类加载器
ClassLoader classLoader = findClassLoader();
//通过spi得到适配编译器
org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
//编译生成源码
return compiler.compile(code, classLoader);
}
createAdaptiveExtensionClassCode
这是一个很大的方法,其实完全可以不必看源码,看一下网上的一下例子就能大概知道生成的源码具体是什么样的格式了。不存在有Adaptive
注解的扩展类,那么必须在接口上存在Adaptive
注解的方法,并且该方法必须要有url
(这也是dubbo很重要的一个组成)类型的入参或者入参得到url的方法。调用没有该注解的方法会抛出异常,有该注解的方法会生成源码,源码的具体逻辑即是通过url得到具体的实现类,当这一步还没有找到具体实现类时就使用默认扩展,然后去调用相同的方法。
private String createAdaptiveExtensionClassCode() {
StringBuilder codeBuilder = new StringBuilder();
Method[] methods = type.getMethods();
boolean hasAdaptiveAnnotation = false;
//遍历接口的所有方法,判断是否在方法上有Adaptive注解
for (Method m : methods) {
if (m.isAnnotationPresent(Adaptive.class)) {
hasAdaptiveAnnotation = true;
break;
}
}
// no need to generate adaptive class since there's no adaptive method found.
if (!hasAdaptiveAnnotation)
throw new IllegalStateException("No adaptive method on extension " + type.getName() + ", refuse to create the adaptive class!");
//包名
codeBuilder.append("package ").append(type.getPackage().getName()).append(";");
//import ExtensionLoader
codeBuilder.append("\nimport ").append(ExtensionLoader.class.getName()).append(";");
//类名为接口+$Adaptive,然后 implements 接口
codeBuilder.append("\npublic class ").append(type.getSimpleName()).append("$Adaptive").append(" implements ").append(type.getCanonicalName()).append(" {");
//log对象
codeBuilder.append("\nprivate static final org.apache.dubbo.common.logger.Logger logger = org.apache.dubbo.common.logger.LoggerFactory.getLogger(ExtensionLoader.class);");
//原子int
codeBuilder.append("\nprivate java.util.concurrent.atomic.AtomicInteger count = new java.util.concurrent.atomic.AtomicInteger(0);\n");
//遍历所有方法
for (Method method : methods) {
//返回类型
Class> rt = method.getReturnType();
//参数类型
Class>[] pts = method.getParameterTypes();
//抛出异常类型
Class>[] ets = method.getExceptionTypes();
Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class);
StringBuilder code = new StringBuilder(512);
//没有Adaptive注解抛出UnsupportedOperationException异常
if (adaptiveAnnotation == null) {
code.append("throw new UnsupportedOperationException(\"method ")
.append(method.toString()).append(" of interface ")
.append(type.getName()).append(" is not adaptive method!\");");
} else {
//找到url类型的入参位置
int urlTypeIndex = -1;
for (int i = 0; i < pts.length; ++i) {
if (pts[i].equals(URL.class)) {
urlTypeIndex = i;
break;
}
}
//找到url类型的入参就判断url是否为null,为空抛出异常
if (urlTypeIndex != -1) {
String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"url == null\");",
urlTypeIndex);
code.append(s);
s = String.format("\n%s url = arg%d;", URL.class.getName(), urlTypeIndex);
code.append(s);
} else {
String attribMethod = null;
//遍历所有参数的所有public方法
LBL_PTS:
for (int i = 0; i < pts.length; ++i) {
Method[] ms = pts[i].getMethods();
for (Method m : ms) {
String name = m.getName();
//依次判断方法是否以get开头,长度大于3,是否是public,是否非静态方法,是否无需入参,是否返回类型是URL
if ((name.startsWith("get") || name.length() > 3)
&& Modifier.isPublic(m.getModifiers())
&& !Modifier.isStatic(m.getModifiers())
&& m.getParameterTypes().length == 0
&& m.getReturnType() == URL.class) {
urlTypeIndex = i;
attribMethod = name;
break LBL_PTS;
}
}
}
//不能得到url,抛出异常
if (attribMethod == null) {
throw new IllegalStateException("fail to create adaptive class for interface " + type.getName()
+ ": not found url parameter or url attribute in parameters of method " + method.getName());
}
//该参数非空,该参数得到的url为空
String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"%s argument == null\");",
urlTypeIndex, pts[urlTypeIndex].getName());
code.append(s);
s = String.format("\nif (arg%d.%s() == null) throw new IllegalArgumentException(\"%s argument %s() == null\");",
urlTypeIndex, attribMethod, pts[urlTypeIndex].getName(), attribMethod);
code.append(s);
//拿到url
s = String.format("%s url = arg%d.%s();", URL.class.getName(), urlTypeIndex, attribMethod);
code.append(s);
}
//拿到Adaptive注解的属性,这里的属性值是用来从url中查值用的
String[] value = adaptiveAnnotation.value();
//如果没有,就将接口的名字根据驼峰命名拆开,首字符转为小写,中间加.
if (value.length == 0) {
char[] charArray = type.getSimpleName().toCharArray();
StringBuilder sb = new StringBuilder(128);
for (int i = 0; i < charArray.length; i++) {
if (Character.isUpperCase(charArray[i])) {
if (i != 0) {
sb.append(".");
}
sb.append(Character.toLowerCase(charArray[i]));
} else {
sb.append(charArray[i]);
}
}
value = new String[]{sb.toString()};
}
//是否有Invocation类型的参数,判断为空
boolean hasInvocation = false;
for (int i = 0; i < pts.length; ++i) {
if (pts[i].getName().equals("org.apache.dubbo.rpc.Invocation")) {
// Null Point check
String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"invocation == null\");", i);
code.append(s);
s = String.format("\nString methodName = arg%d.getMethodName();", i);
code.append(s);
hasInvocation = true;
break;
}
}
//默认扩展类名字
String defaultExtName = cachedDefaultName;
String getNameCode = null;
//倒叙排列所有的值,保证了从url中取值的优先顺序是从第一个到最后一个
for (int i = value.length - 1; i >= 0; --i) {
//最后一个将默认值传入
if (i == value.length - 1) {
if (null != defaultExtName) {
if (!"protocol".equals(value[i]))
//有Invocation入参通过getMethodParameter取值
if (hasInvocation)
getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName);
else
getNameCode = String.format("url.getParameter(\"%s\", \"%s\")", value[i], defaultExtName);
//protocol在url中使用特殊的方法取值的
else
getNameCode = String.format("( url.getProtocol() == null ? \"%s\" : url.getProtocol() )", defaultExtName);
} else {
if (!"protocol".equals(value[i]))
if (hasInvocation)
getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName);
else
getNameCode = String.format("url.getParameter(\"%s\")", value[i]);
else
getNameCode = "url.getProtocol()";
}
} else {
if (!"protocol".equals(value[i]))
if (hasInvocation)
getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName);
else
getNameCode = String.format("url.getParameter(\"%s\", %s)", value[i], getNameCode);
else
getNameCode = String.format("url.getProtocol() == null ? (%s) : url.getProtocol()", getNameCode);
}
}
code.append("\nString extName = ").append(getNameCode).append(";");
//判断是否从url得到值,并且默认值为空
String s = String.format("\nif(extName == null) " +
"throw new IllegalStateException(\"Fail to get extension(%s) name from url(\" + url.toString() + \") use keys(%s)\");",
type.getName(), Arrays.toString(value));
code.append(s);
//extension作为拿到的扩展的属性名,通过try catch从ExtensionLoader拿到指定的扩展类
code.append(String.format("\n%s extension = null;\n try {\nextension = (% 0) {
codeBuilder.append(", ");
}
codeBuilder.append(pts[i].getCanonicalName());
codeBuilder.append(" ");
codeBuilder.append("arg").append(i);
}
codeBuilder.append(")");
if (ets.length > 0) {
codeBuilder.append(" throws ");
for (int i = 0; i < ets.length; i++) {
if (i > 0) {
codeBuilder.append(", ");
}
codeBuilder.append(ets[i].getCanonicalName());
}
}
codeBuilder.append(" {");
codeBuilder.append(code.toString());
codeBuilder.append("\n}");
}
codeBuilder.append("\n}");
//debug打印
if (logger.isDebugEnabled()) {
logger.debug(codeBuilder.toString());
}
return codeBuilder.toString();
}
只要开启debug级别日志,就能看到生成的扩展实现,这里我贴一个Dispatcher
接口的适配源码。
import org.apache.dubbo.common.extension.ExtensionLoader;
public class Dispatcher$Adaptive implements org.apache.dubbo.remoting.Dispatcher {
private static final org.apache.dubbo.common.logger.Logger logger = org.apache.dubbo.common.logger.LoggerFactory.getLogger(ExtensionLoader.class);
private java.util.concurrent.atomic.AtomicInteger count = new java.util.concurrent.atomic.AtomicInteger(0);
public org.apache.dubbo.remoting.ChannelHandler dispatch(org.apache.dubbo.remoting.ChannelHandler arg0, org.apache.dubbo.common.URL arg1) {
if (arg1 == null)
throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg1;
String extName = url.getParameter("dispatcher", url.getParameter("dispather", url.getParameter("channel.handler", "all")));
if(extName == null)
throw new IllegalStateException("Fail to get extension(org.apache.dubbo.remoting.Dispatcher) name from url(" + url.toString() + ") use keys([dispatcher, dispather, channel.handler])");
org.apache.dubbo.remoting.Dispatcher extension = null;
try {
extension = (org.apache.dubbo.remoting.Dispatcher)ExtensionLoader.getExtensionLoader(org.apache.dubbo.remoting.Dispatcher.class).getExtension(extName);
}catch(Exception e){
if (count.incrementAndGet() == 1) {
logger.warn("Failed to find extension named " + extName + " for type org.apache.dubbo.remoting.Dispatcher, will use default extension all instead.", e);
}
extension = (org.apache.dubbo.remoting.Dispatcher)ExtensionLoader.getExtensionLoader(org.apache.dubbo.remoting.Dispatcher.class).getExtension("all");
}
return extension.dispatch(arg0, arg1);
}
}