dubbo的自适应扩展机制

2020-08-09T12:09:10
关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9

注解@Adaptive

在dubbo中,为了灵活的适配一个接口的多种实现,而不是通过硬编码来指定用哪个实现,提供了@Adaptive注解。这个注解看的出,在类以及方法上使用的。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Adaptive {
    
    String[] value() default {};
}

源码分析

getAdaptiveExtension

从缓存中获取,没有则创建

public T getAdaptiveExtension() {
    Object instance = cachedAdaptiveInstance.get();
    // 缓存为空
    if (instance == null) {
        if (createAdaptiveInstanceError != null) {
            throw new IllegalStateException("Failed to create adaptive instance: " +
                    createAdaptiveInstanceError.toString(),
                    createAdaptiveInstanceError);
        }
        // 创建
        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);
                }
            }
        }
    }

    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() {
    // 获取SPI信息
    getExtensionClasses();
    // 缓存有,则返回
    if (cachedAdaptiveClass != null) {
        return cachedAdaptiveClass;
    }
    // 没有则创建
    return cachedAdaptiveClass = createAdaptiveExtensionClass();
}

createAdaptiveExtensionClass

private Class<?> createAdaptiveExtensionClass() {
    // 拼接代码
    String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
    // 获取类加载器
    ClassLoader classLoader = findClassLoader();
    // 获取编译器,javassist用于动态编程
    org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
    // 把代码编译成class
    return compiler.compile(code, classLoader);
}

为了方便后面源码参考,先贴出拼接好的代码(我这边以Protocol为例)

package org.apache.dubbo.rpc;

import org.apache.dubbo.common.extension.ExtensionLoader;

public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol {
    public void destroy() {
        throw new UnsupportedOperationException("The method public abstract " +
                "void org.apache.dubbo.rpc.Protocol.destroy() of " +
                "interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }

    public int getDefaultPort() {
        throw new UnsupportedOperationException("The method public abstract int " +
                "org.apache.dubbo.rpc.Protocol.getDefaultPort() of " +
                "interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }

    public org.apache.dubbo.rpc.Exporter export(org.apache.dubbo.rpc.Invoker arg0)
            throws org.apache.dubbo.rpc.RpcException {
        if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
        if (arg0.getUrl() == null)
            throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
        org.apache.dubbo.common.URL url = arg0.getUrl();
        String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        if (extName == null)
            throw new IllegalStateException("Failed to get extension " +
                    "(org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
        org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.
                getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.export(arg0);
    }

    public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, org.apache.dubbo.common.URL arg1)
            throws org.apache.dubbo.rpc.RpcException {
        if (arg1 == null) throw new IllegalArgumentException("url == null");
        org.apache.dubbo.common.URL url = arg1;
        String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        if (extName == null)
            throw new IllegalStateException("Failed to get extension " +
                    "(org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
        org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.
                getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.refer(arg0, arg1);
    }
}

AdaptiveClassCodeGenerator.generate

public String generate() {
    // no need to generate adaptive class since there's no adaptive method found.
    // 至少一个方法是有Adaptive注解
    if (!hasAdaptiveMethod()) {
        throw new IllegalStateException("No adaptive method exist on extension " + type.getName() + ", refuse to create the adaptive class!");
    }

    StringBuilder code = new StringBuilder();
    // 拼接package信息
    code.append(generatePackageInfo());
    // 拼接Imports信息
    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();
}

AdaptiveClassCodeGenerator.generateMethod

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);
}

其他比较简单,我们只看generateMethodContent

AdaptiveClassCodeGenerator.generateMethodContent

主要是方法体的代码拼接

private String generateMethodContent(Method method) {
    Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class);
    StringBuilder code = new StringBuilder(512);
    // 不是Adaptive注解的,方法体内抛异常,详情见拼接好的代码
    if (adaptiveAnnotation == null) {
        return generateUnsupported(method);
    } else {
        // 获取url的位置
        int urlTypeIndex = getUrlTypeIndex(method);

        // found parameter in URL type
        if (urlTypeIndex != -1) {
            // Null Point check
            // 拼接判断参数是否为空,参考拼接好的refer方法
            code.append(generateUrlNullCheck(urlTypeIndex));
        } else {
            // did not find parameter in URL type
            // 不存在URL,方法体中判断是否有某个参数的某个方法有URL返回,
            // 有的话,则返回的字符串参考拼接好的代码,没有的话,雷同上面抛异常的拼接字符串,参考拼接好的export方法
            // 这个方法,必须是方法名以 get 开头,或方法名大于3个字符,方法的访问权限为 public,
            // 非静态方法,方法参数数量为0,方法返回值类型为 URL,不符合抛异常
            code.append(generateUrlAssignmentIndirectly(method));
        }
        // 如果没有值,获取类名的小写
        String[] value = getMethodAdaptiveValue(adaptiveAnnotation);
        // 是否有Invocation 类型的参数
        boolean hasInvocation = hasInvocationArgument(method);
        // 有的话,则拼接判断是否为空的异常代码
        code.append(generateInvocationArgumentNullCheck(method));
        // String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        code.append(generateExtNameAssignment(value, hasInvocation));
        // check extName == null?
        // 拼接extName == null这行
        code.append(generateExtNameNullCheck(value));
        // 拼接getExtension这行
        code.append(generateExtensionAssignment());

        // return statement
        //  拼接返回值的最后一行
        code.append(generateReturnAndInvocation(method));
    }

    return code.toString();
}
扫一扫关注公众号添加购物返利助手,领红包
当前页面是本站的「Baidu MIP」版。发表评论请点击:完整版 »
因本文不是用Markdown格式的编辑器书写的,转换的页面可能不符合MIP标准。