Dubbo源码分析之扩展机制(2)

版权声明: https://blog.csdn.net/ph3636/article/details/91372020

当没有设置自适应类型时动态创建自定义类


private Class<?> createAdaptiveExtensionClass() {
    String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
    ClassLoader classLoader = findClassLoader();
    org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
    return compiler.compile(code, classLoader);
}

生成并返回自适应类的具体代码


public String generate() {
    // no need to generate adaptive class since there's no adaptive method found.
    if (!hasAdaptiveMethod()) {
        throw new IllegalStateException("No adaptive method exist on extension " + type.getName() + ", refuse to create the adaptive class!");
    }

    StringBuilder code = new StringBuilder();
    code.append(generatePackageInfo());
    code.append(generateImports());
    code.append(generateClassDeclaration());
    
    Method[] methods = type.getMethods();
    for (Method method : methods) {
        code.append(generateMethod(method));
    }
    code.append("}");
    
    if (logger.isDebugEnabled()) {
        logger.debug(code.toString());
    }
    return code.toString();
}

判断该接口类型的方法中是否含有任意一个带有自适应注解的方法


private boolean hasAdaptiveMethod() {
    return Arrays.stream(type.getMethods()).anyMatch(m -> m.isAnnotationPresent(Adaptive.class));
}

生成包信息


private static final String CODE_PACKAGE = "package %s;\n";

private String generatePackageInfo() {
    return String.format(CODE_PACKAGE, type.getPackage().getName());
}

生成导入信息


private static final String CODE_IMPORTS = "import %s;\n";

private String generateImports() {
    return String.format(CODE_IMPORTS, ExtensionLoader.class.getName());
}

生成类声明信息


private static final String CODE_CLASS_DECLARATION = "public class %s$Adaptive implements %s {\n";

private String generateClassDeclaration() {
    return String.format(CODE_CLASS_DECLARATION, type.getSimpleName(), type.getCanonicalName());
}

生成方法信息


private String generateMethod(Method method) {
    String methodReturnType = method.getReturnType().getCanonicalName();
    String methodName = method.getName();
    String methodContent = generateMethodContent(method);
    String methodArgs = generateMethodArguments(method);
    String methodThrows = generateMethodThrows(method);
    return String.format(CODE_METHOD_DECLARATION, methodReturnType, methodName, methodArgs, methodThrows, methodContent);
}

分别获取方法名字,具体内容,参数,异常信息,返回类型


private static final String CODE_METHOD_DECLARATION = "public %s %s(%s) %s {\n%s}\n";
private static final String CODE_METHOD_ARGUMENT = "%s arg%d";
private static final String CODE_METHOD_THROWS = "throws %s";

private String generateMethodArguments(Method method) {
    Class<?>[] pts = method.getParameterTypes();
    return IntStream.range(0, pts.length)
                    .mapToObj(i -> String.format(CODE_METHOD_ARGUMENT, pts[i].getCanonicalName(), i))
                    .collect(Collectors.joining(", "));
}

private String generateMethodThrows(Method method) {
    Class<?>[] ets = method.getExceptionTypes();
    if (ets.length > 0) {
        String list = Arrays.stream(ets).map(Class::getCanonicalName).collect(Collectors.joining(", "));
        return String.format(CODE_METHOD_THROWS, list);
    } else {
        return "";
    }
}

生成方法具体内容

private String generateMethodContent(Method method) {
    Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class);
    StringBuilder code = new StringBuilder(512);
    if (adaptiveAnnotation == null) {
        return generateUnsupported(method);
    } else {
        int urlTypeIndex = getUrlTypeIndex(method);
        
        // found parameter in URL type
        if (urlTypeIndex != -1) {
            // Null Point check
            code.append(generateUrlNullCheck(urlTypeIndex));
        } else {
            // did not find parameter in URL type
            code.append(generateUrlAssignmentIndirectly(method));
        }

        String[] value = getMethodAdaptiveValue(adaptiveAnnotation);

        boolean hasInvocation = hasInvocationArgument(method);
        
        code.append(generateInvocationArgumentNullCheck(method));
        
        code.append(generateExtNameAssignment(value, hasInvocation));
        // check extName == null?
        code.append(generateExtNameNullCheck(value));
        
        code.append(generateExtensionAssignment());

        // return statement
        code.append(generateReturnAndInvocation(method));
    }
    
    return code.toString();
}

判断该方法是否带有自适应注解,没带的话设置不支持操作


private static final String CODE_UNSUPPORTED = "throw new UnsupportedOperationException(\"The method %s of interface %s is not adaptive method!\");\n";

private String generateUnsupported(Method method) {
    return String.format(CODE_UNSUPPORTED, method, type.getName());
}

获取URL参数所处的下标

扫描二维码关注公众号,回复: 6751365 查看本文章

private int getUrlTypeIndex(Method method) {            
    int urlTypeIndex = -1;
    Class<?>[] pts = method.getParameterTypes();
    for (int i = 0; i < pts.length; ++i) {
        if (pts[i].equals(URL.class)) {
            urlTypeIndex = i;
            break;
        }
    }
    return urlTypeIndex;
}

如果该方法有URL参数的话,进行判空检查


private static final String CODE_URL_NULL_CHECK = "if (arg%d == null) throw new IllegalArgumentException(\"url == null\");\n%s url = arg%d;\n";

private String generateUrlNullCheck(int index) {
    return String.format(CODE_URL_NULL_CHECK, index, URL.class.getName(), index);
}

没有的话就判断参数的方法中是否包含有返回值为URL的方法

private String generateUrlAssignmentIndirectly(Method method) {
    Class<?>[] pts = method.getParameterTypes();
    
    // find URL getter method
    for (int i = 0; i < pts.length; ++i) {
        for (Method m : pts[i].getMethods()) {
            String name = m.getName();
            if ((name.startsWith("get") || name.length() > 3)
                    && Modifier.isPublic(m.getModifiers())
                    && !Modifier.isStatic(m.getModifiers())
                    && m.getParameterTypes().length == 0
                    && m.getReturnType() == URL.class) {
                return generateGetUrlNullCheck(i, pts[i], name);
            }
        }
    }
    
    // getter method not found, throw
    throw new IllegalStateException("Failed to create adaptive class for interface " + type.getName()
                    + ": not found url parameter or url attribute in parameters of method " + method.getName());

}

对参数的方法进行判空处理


private String generateGetUrlNullCheck(int index, Class<?> type, String method) {
    // Null point check
    StringBuilder code = new StringBuilder();
    code.append(String.format("if (arg%d == null) throw new IllegalArgumentException(\"%s argument == null\");\n",
            index, type.getName()));
    code.append(String.format("if (arg%d.%s() == null) throw new IllegalArgumentException(\"%s argument %s() == null\");\n",
            index, method, type.getName(), method));

    code.append(String.format("%s url = arg%d.%s();\n", URL.class.getName(), index, method));
    return code.toString();
}

获取方法自适应注解值默认值是分离的类型名字


private String[] getMethodAdaptiveValue(Adaptive adaptiveAnnotation) {
    String[] value = adaptiveAnnotation.value();
    // value is not set, use the value generated from class name as the key
    if (value.length == 0) {
        String splitName = StringUtils.camelToSplitName(type.getSimpleName(), ".");
        value = new String[]{splitName};
    }
    return value;
}

判断是否包含Invocation参数


private static final String CLASSNAME_INVOCATION = "org.apache.dubbo.rpc.Invocation";

private boolean hasInvocationArgument(Method method) {
    Class<?>[] pts = method.getParameterTypes();
    return Arrays.stream(pts).anyMatch(p -> CLASSNAME_INVOCATION.equals(p.getName()));
}

对Invocation参数进行判空处理以及获取methodName值


private static final String CODE_INVOCATION_ARGUMENT_NULL_CHECK = "if (arg%d == null) throw new IllegalArgumentException(\"invocation == null\"); "
                    + "String methodName = arg%d.getMethodName();\n";

private String generateInvocationArgumentNullCheck(Method method) {
    Class<?>[] pts = method.getParameterTypes();
    return IntStream.range(0, pts.length).filter(i -> CLASSNAME_INVOCATION.equals(pts[i].getName()))
                    .mapToObj(i -> String.format(CODE_INVOCATION_ARGUMENT_NULL_CHECK, i, i))
                    .findFirst().orElse("");
}

获取扩展名字分配规则代码,根据不同的情况组合成不同的代码

private static final String CODE_EXT_NAME_ASSIGNMENT = "String extName = %s;\n";

private String generateExtNameAssignment(String[] value, boolean hasInvocation) {
    // TODO: refactor it
    String getNameCode = null;
    for (int i = value.length - 1; i >= 0; --i) {
        if (i == value.length - 1) {
            if (null != defaultExtName) {
                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], defaultExtName);
                    }
                } 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);
            }
        }
    }
    
    return String.format(CODE_EXT_NAME_ASSIGNMENT, getNameCode);
}

对扩展名字进行判断检查


private static final String CODE_EXT_NAME_NULL_CHECK = "if(extName == null) "
                    + "throw new IllegalStateException(\"Failed to get extension (%s) name from url (\" + url.toString() + \") use keys(%s)\");\n";

private String generateExtNameNullCheck(String[] value) {
    return String.format(CODE_EXT_NAME_NULL_CHECK, type.getName(), Arrays.toString(value));
}

从该类型的扩展加载器中获取指定名字的实例信息


private static final String CODE_EXTENSION_ASSIGNMENT = "%s extension = (%<s)%s.getExtensionLoader(%s.class).getExtension(extName);\n";

private String generateExtensionAssignment() {
    return String.format(CODE_EXTENSION_ASSIGNMENT, type.getName(), ExtensionLoader.class.getSimpleName(), type.getName());
}

生成返回信息并执行对应的方法。

private String generateReturnAndInvocation(Method method) {
    String returnStatement = method.getReturnType().equals(void.class) ? "" : "return ";
    
    String args = Arrays.stream(method.getParameters()).map(Parameter::getName).collect(Collectors.joining(", "));

    return returnStatement + String.format("extension.%s(%s);\n", method.getName(), args);
}

猜你喜欢

转载自blog.csdn.net/ph3636/article/details/91372020