Dubbo-自适应拓展机制

背景

    在 Dubbo 中,不少拓展都是经过 SPI 机制进行加载的,好比 Protocol、Cluster、LoadBalance 等,这些都是Dubbo的基础组件。这些基础组件的拓展不是在系统框架启动阶段被加载,而是拓展方法被调用时,根据运行时参数(URL)进行动态加载的。自适应拓展机制是创建在SPI基础之上的,自适应拓展类的核心实现:在拓展接口的方法被调用时,经过SPI加载具体的拓展实现类,并调用拓展对象的同名方法。能够看到自适应拓展是创建在SPI基础上的实现的功能,自适应拓展加上SPI实现Dubbo可拓展和解耦,这是Dubbo很是重要机制。java

    自适应拓展类的过程是:选根据接口方法上的"@Adaptive" 注解生成自适应代码,而后经过Javassist编译建立自适应拓展类代码(使用系统内置特殊的自适应拓展类),再经过反射建立自适应拓展类的实例,而且保存至缓存。须要注意系统内置特殊的自适应拓展类是,分别是 AdaptiveCompiler 和 AdaptiveExtensionFactory,由于这两个类的类被 Adaptive 注解了(是类被注解,而不是方法)。Dubbo这样设计的缘由是:在产生自适应拓展类代码时,为了不死循环产生自适应拓展类代码,这一点很重要,特别是新手很容易搞混淆。apache

代码分析

建立自适应拓展类实例-逻辑图

    这里以"org.apache.dubbo.rpc.Protocol"做为示例讲解下建立自适应拓展类的逻辑,由于这部分功能逻辑单纯从代码上看很容易搞错顺序或关系,因此单独拿出来解释下。设计模式

    代码入口是"ExtensionLoader.getExtensionLoader"和SPI章节入口是同样的,但咱们要了解的内容不同。下面是获取ExtensionLoader实例的代码在SPI章节讲解过,这里就不啰嗦了。缓存

@SuppressWarnings("unchecked")
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
    logger.info("type:"+type);
    //空值判断
    if (type == null) {
        throw new IllegalArgumentException("Extension type == null");
    }

    //判断是否接口类
    if (!type.isInterface()) {
        throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
    }
    // 即:type.isAnnotationPresent(SPI.class),是否包含SPI注解
    if (!withExtensionAnnotation(type)) {
        throw new IllegalArgumentException("Extension type (" + type +
                ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
    }

    //new ExtensionLoader()时,
    //触发ExtensionFactory的ExtensionLoader
    // 实例建立:ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    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;
}

    只是有一点,ExtensionLoader的私用构造方法还有其它代码逻辑,也就是在初始化其它扩展类的ExtensionLoader实例以前,必须先初始化ExtensionFactory.class的ExtensionLoader实例。app

private ExtensionLoader(Class<?> type) {
    this.type = type;
    //先执行:ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension(),即获得AdaptiveExtensionFactory
    //ExtensionFactory的objectFactory属性为空
    //非ExtensionFactory的objectFactory属性为AdaptiveExtensionFactory
    objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}

    ExtensionFactory.class在获取自适应拓展类实例时,由于ExtensionFactory.class的字类AdaptiveExtensionFactory有“@Adaptive”,因此AdaptiveExtensionFactory直接返回而且成为自适应拓展类,这是特殊的例子。框架

    在获取自适应拓展类实例,先是从缓存获取,若是缓存没有命中,再建立。由于建立一个自适应拓展类实例太耗资源和时间了,因此这些对象都是以单例方式运行。dom

@SuppressWarnings("unchecked")
public T getAdaptiveExtension() {
    logger.info("getAdaptiveExtension.type:"+type);
    // 从缓存中获取自适应拓展
    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("Failed to create adaptive instance: " + t.toString(), t);
                    }
                }
            }
        } else {
            throw new IllegalStateException("Failed to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
        }
    }

    return (T) instance;
}

    这里和SPI同样,均使用了Dubbo的IOC,在注入依赖以前先获取自适应类,并建立实例。ide

@SuppressWarnings("unchecked")
private T createAdaptiveExtension() {
    try {
        //获取自适应拓展类,而后建立实例,并经过反射注入该实例的依赖(Dubbo的IOC实现)
        return injectExtension((T) getAdaptiveExtensionClass().newInstance());
    } catch (Exception e) {
        throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
    }
}

这个方法包含三个逻辑性能

  • 先加载SPI 全部的拓展类,这个SPI章节详细展开过。
  • 判断cachedAdaptiveClass属性是否为空,若是不为空直接返回cachedAdaptiveClass,即自适应拓展类为cachedAdaptiveClass。cachedAdaptiveClass就表明着那些拓展类上面标注"@Adaptive"注释。
  • 建立自适应扩展类的代码,而后经过Javassist编译,并经过反射获得自适应拓展对象。
private Class<?> getAdaptiveExtensionClass() {
    // 获取全部的拓展类
    getExtensionClasses();
    // 加载完全部的实现以后,若是发现有cachedAdaptiveClass不为空,则直接返回缓存,
    // 同时也意味着自拓展适应类:cachedAdaptiveClass是AdaptiveExtensionFactory或AdaptiveCompiler
    if (cachedAdaptiveClass != null) {
        return cachedAdaptiveClass;
    }
    // 建立自适应拓展类
    return cachedAdaptiveClass = createAdaptiveExtensionClass();
}

    先获取指定类(如:"org.apache.dubbo.rpc.Protocol")全部的拓展类,在获取拓展类时,判断拓展类是否标注了"@Adaptive",若是标注了"@Adaptive"表示当前类为自适应拓展类,不须要经过动态生成代码建立自适应拓展类。如:AdaptiveExtensionFactory和AdaptiveCompiler。ui

private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
    //检查clazz(扩展实现类)是否type(接口)的实现类
    if (!type.isAssignableFrom(clazz)) {
        throw new IllegalStateException("Error occurred when loading extension class (interface: " +
                type + ", class line: " + clazz.getName() + "), class "
                + clazz.getName() + " is not subtype of interface.");
    }
    // 检测目标类上是否有 Adaptive 注解,若是有则设置 cachedAdaptiveClass缓存
    if (clazz.isAnnotationPresent(Adaptive.class)) {
        cacheAdaptiveClass(clazz);
    // 检测 clazz 是不是 Wrapper 类型,若是有则存储 clazz 到 cachedWrapperClasses 缓存中
    } else if (isWrapperClass(clazz)) {
        //判断是不是wrapper类型(包装类型),实现类的构造方法中的参数是扩展点类型的,就是一个Wrapper类
        cacheWrapperClass(clazz);
    } else {// 程序进入此分支,代表 clazz 是一个普通的拓展类
        // 获取默认的构造方法
        clazz.getConstructor();
        if (StringUtils.isEmpty(name)) {//name即Key值,如:spi=org.apache.dubbo.common.extension.factory.SpiExtensionFactory
            // 若是 name 为空,则尝试从 Extension 注解中获取 name,或使用小写的类名做为 name
            name = findAnnotationName(clazz);
            if (name.length() == 0) {
                throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
            }
        }
        String[] names = NAME_SEPARATOR.split(name);// 切分 name
        if (ArrayUtils.isNotEmpty(names)) {
            cacheActivateClass(clazz, names[0]);
            for (String n : names) {
                cacheName(clazz, n);// 存储 Class 到名称的映射关系
                saveInExtensionClass(extensionClasses, clazz, n);//缓存Name与Clazz映谢关系
            }
        }
    }
}
private void cacheAdaptiveClass(Class<?> clazz) {
    if (cachedAdaptiveClass == null) {
        // 设置 cachedAdaptiveClass缓存,并且这个类只有一个,也就是在指定的扩展类范围只能有一个类能够标注“@Adaptive”
        cachedAdaptiveClass = clazz;
    } else if (!cachedAdaptiveClass.equals(clazz)) {
        throw new IllegalStateException("More than 1 adaptive class found: "
                + cachedAdaptiveClass.getClass().getName()
                + ", " + clazz.getClass().getName());
    }
}

    若是全部拓展实现类都没有合适标注"@Adaptive",那建立自适应拓展类的代码。这个方法详细解释了为何须要 AdaptiveCompiler 和 AdaptiveExtensionFactory的缘由。

private Class<?> createAdaptiveExtensionClass() {
    // 构建自适应拓展代码
    String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
    // 获取类加载器
    ClassLoader classLoader = findClassLoader();
    //dubbo默认使用javassist获取编译器
    //若是没有AdaptiveExtensionFactory和AdaptiveCompiler这两个类,那cachedAdaptiveClass一直为空,这个方法就会一直是死循环
    //这也是Dubbo有会把@Adaptive标注类上面的缘由。
    //解析Compiler的实现类的时候,会在getAdaptiveExtensionClass中直接返回AdaptiveCompiler,不须要动态生成代码
    org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.
            getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();

    // 编译代码,生成 Class
    return compiler.compile(code, classLoader);
}

生成自适应拓展代码-逻辑图

    产生自适应拓展类代码的逻辑比较复杂,涉及到的细节也比较多,这里以"org.apache.dubbo.rpc.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.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);
    }

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

    要产生自适应拓展类的接口至少有一个方法被标注了"@Adaptive",不然不产生代任何码。由于在这个方法前面已经排除类的标注了,这里只须要确认方法有注解就好了。

public String generate() {
    //Dubbo 要求该接口至少有一个方法被 Adaptive 注解修饰
    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());//生成包代码,如:package org.apache.dubbo.rpc;
    code.append(generateImports());//生成import代码,如import org.apache.dubbo.common.extension.ExtensionLoader;
    code.append(generateClassDeclaration());//生成声明类代码,如:public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol {

    // 经过反射获取全部的方法
    Method[] methods = type.getMethods();
    // 遍历方法列表
    for (Method method : methods) {
        code.append(generateMethod(method));
    }
    code.append("}");

    if (logger.isDebugEnabled()) {
        logger.debug(code.toString());
    }
    logger.info("\n\n  code.toString:"+code.toString());
    return code.toString();
}

    产生代码的重点在于方法,产生方法的时须要根据参数判断和逻辑处理,相对复杂。

/**
 * generate method declaration
 * 生成"方法"代码逻辑
 */
private String generateMethod(Method method) {
    //返回参数类型,如:org.apache.dubbo.rpc.Exporter
    String methodReturnType = method.getReturnType().getCanonicalName();
    //方法名代码,如:export
    String methodName = method.getName();
    //方法内容代码
    String methodContent = generateMethodContent(method);
    //方法参数代码,如:org.apache.dubbo.rpc.Invoker arg0
    String methodArgs = generateMethodArguments(method);
    //抛异常代码,如:throws org.apache.dubbo.rpc.RpcException
    String methodThrows = generateMethodThrows(method);
    return String.format(CODE_METHOD_DECLARATION, methodReturnType, methodName, methodArgs, methodThrows, methodContent);
}

    产生方法代码时,首先产生是没有标注 "@Adaptive"方法的逻辑,而后须要直接处理参数URL或间接处理URL参数,如:判断是否为空,判断参数的属性getURL方法等。若是全部参数都不直接包含URL或间接包含URL参数,就直接抛异常。URL是Dubbo在每一个层流转过程当中,用于上传下达传递参数的,是一个很重要的数据类型。

private String generateMethodContent(Method method) {
    //获取方法上Adaptive注解
    Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class);
    StringBuilder code = new StringBuilder(512);
    //没有标注 Adaptive 注解的方法生成代理逻辑:仅会生成一句抛出异常的代码。
    // throw new UnsupportedOperationException("The method
    if (adaptiveAnnotation == null) {
        return generateUnsupported(method);
    } else {
        // 遍历参数列表,肯定 org.apache.dubbo.common.URL在方法参数位置
        int urlTypeIndex = getUrlTypeIndex(method);

        // urlTypeIndex != -1,表示参数列表中存在 URL 参数
        // found parameter in URL type
        if (urlTypeIndex != -1) {
            // 为 URL 类型参数生成判空代码,格式以下:
            // if (arg1 == null) throw new IllegalArgumentException("url == null");
            code.append(generateUrlNullCheck(urlTypeIndex));
        } else {
            // did not find parameter in URL type
            //若是参数不包括URL,那从参数的属性应该包含URL,若是参数的属性不包含URL属性,那抛异常,如:
            //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");
            code.append(generateUrlAssignmentIndirectly(method));
        }

        //获取 Adaptive 注解值,若是不存在,采用类名,如:LoadBalance 通过处理后,获得 load.balance
        String[] value = getMethodAdaptiveValue(adaptiveAnnotation);

        //检测方法列表中是否存在 org.apache.dubbo.rpc.Invocation 类型的参数
        boolean hasInvocation = hasInvocationArgument(method);

        // append代码:为Invocation 类型参数生成判空代码
        code.append(generateInvocationArgumentNullCheck(method));

        //append代码:生成拓展名获取逻辑代码
        // String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
        code.append(generateExtNameAssignment(value, hasInvocation));

        // 生成 extName 判空代码
        //if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
        code.append(generateExtNameNullCheck(value));

        //生成拓展获取代码
        //如:org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
        code.append(generateExtensionAssignment());

        //生成返回值代码
        //return extension.export(arg0);
        code.append(generateReturnAndInvocation(method));
    }

    return code.toString();
}

    经过反射方法获取方法名称、访问权限、方法参数数量,而后判断参数是否包括getUrl方法。

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()) {
            // 遍历方法列表,寻找可返回 URL 的 getter 方法
            String name = m.getName();
            // 1. 方法名以 get 开头,或方法名大于3个字符
            // 2. 方法的访问权限为 public
            // 3. 非静态方法
            // 4. 方法参数数量为0
            // 5. 方法返回值类型为 URL
            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);
            }
        }
    }

    // 若是全部参数中均不包含可返回 URL 的 getter 方法,则抛出异常
    // 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 generateExtNameAssignment(String[] value, boolean hasInvocation) {
    String getNameCode = null;
    // 遍历 value,这里的 value 是 Adaptive 的注解值。
    // 此处循环目的是生成从 URL 中获取拓展名的代码,生成的代码会赋值给 getNameCode 变量。注意这
    // 个循环的遍历顺序是由后向前遍历的。
    for (int i = value.length - 1; i >= 0; --i) {
        if (i == value.length - 1) {
            // 默认拓展名非空
            if (null != defaultExtName) {
                // protocol 是 url 的一部分,可经过 getProtocol 方法获取,其余的则是从
                // URL 参数中获取。由于获取方式不一样,因此这里要判断 value[i] 是否为 protocol
                if (!"protocol".equals(value[i])) {
                    // hasInvocation 用于标识方法参数列表中是否有 Invocation 类型参数
                    if (hasInvocation) {
                        // 生成的代码功能等价于下面的代码:
                        //   url.getMethodParameter(methodName, value[i], defaultExtName)
                        // 以 LoadBalance 接口的 select 方法为例,最终生成的代码以下:
                        //   url.getMethodParameter(methodName, "loadbalance", "random")
                        getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName);
                    } else {
                        // 生成的代码功能等价于下面的代码:
                        //   url.getParameter(value[i], defaultExtName)
                        getNameCode = String.format("url.getParameter(\"%s\", \"%s\")", value[i], defaultExtName);
                    }
                } else {
                    // 生成的代码功能等价于下面的代码:
                    //   ( url.getProtocol() == null ? defaultExtName : url.getProtocol() )
                    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 {
                        // 生成的代码功能等价于下面的代码:
                        //   url.getParameter(value[i])
                        getNameCode = String.format("url.getParameter(\"%s\")", value[i]);
                    }
                } else {
                    // 生成从 url 中获取协议的代码,好比 "dubbo"
                    getNameCode = "url.getProtocol()";
                }
            }
        } else {
            if (!"protocol".equals(value[i])) {
                if (hasInvocation) {
                    // 生成代码格式同上
                    getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName);
                } else {
                    // 生成的代码功能等价于下面的代码:
                    //   url.getParameter(value[i], getNameCode)
                    // 以 Transporter 接口的 connect 方法为例,最终生成的代码以下:
                    //   url.getParameter("client", url.getParameter("transporter", "netty"))
                    getNameCode = String.format("url.getParameter(\"%s\", %s)", value[i], getNameCode);
                }
            } else {
                // 生成的代码功能等价于下面的代码:
                //   url.getProtocol() == null ? getNameCode : url.getProtocol()
                // 以 Protocol 接口的 connect 方法为例,最终生成的代码以下:
                //   url.getProtocol() == null ? "dubbo" : url.getProtocol()
                getNameCode = String.format("url.getProtocol() == null ? (%s) : url.getProtocol()", getNameCode);
            }
        }
    }

    // 生成 extName 赋值代码
    return String.format(CODE_EXT_NAME_ASSIGNMENT, getNameCode);
}

    获得一个完整的自适应拓展类后,自适应拓展类的核心逻辑:在拓展接口的方法被调用时,基于SPI机制而且根据URL或间接的URL参数加载具体的拓展实现类,并调用拓展对象的同名方法。

    最后获得的是String类型自适应拓展类代码,根据String代码建立Class对象和实现,这时候就是轮到Javassit出场了。

@Adaptive
public class AdaptiveCompiler implements Compiler {

    private static volatile String DEFAULT_COMPILER;

    public static void setDefaultCompiler(String compiler) {
        DEFAULT_COMPILER = compiler;
    }

    @Override
    public Class<?> compile(String code, ClassLoader classLoader) {
        Compiler compiler;
        //获得一个ExtensionLoader
        ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);
        //默认的Compiler名字
        String name = DEFAULT_COMPILER; // copy reference
        if (name != null && name.length() > 0) {
            compiler = loader.getExtension(name);
        } else {
            //若是没有设置编译器的扩展名,就使用默认编译器
            //默认值:org.apache.dubbo.common.compiler.support.JavassistCompiler
            compiler = loader.getDefaultExtension();
        }

        //扩展实现类来编译代码
        return compiler.compile(code, classLoader);
    }
}

涉及的知识点

    本章节涉及的知识点有字节码技术,Java主要流行的字节码操纵框架有Javassist 和 ASM。字节码技术主要是Dubbo默认是使用Javassist字节码,Dubbo使用Javassist是基于性能和易用性两方面考虑的。具体能够参考早期 dubbo 的做者梁飞的博客 http://javatar.iteye.com/blog/814426,从这里面也能够知道技术选型的过程和考量点。

    本章节涉及的知识点还有设计模式-代理模式,代理模式在Dubbo中是普遍应用的,Dubbo并无直接使用JDK的代理技术,而是经过Javassist实现代理。代理模式在Dubbo、Spring都是普遍应用, 特别是Dubbo的服务导入与导出部分大量使用。

小结

    本章节涉及到自适应拓展类机制,是Dubbo的重要的基础机制。基于Dubbo的SPI的自适应拓展机制能够动态调用拓展实现类,不少基础组件都依赖些机制Protocol、Cluster、LoadBalance 等。

相关文章
相关标签/搜索