资讯专栏INFORMATION COLUMN

Dubbo的动态编译

sorra / 3308人阅读

摘要:的类继承关系在实现中,默认使用进行动态编译,不使用。那么这个是一个装饰类还是一个动态代理类从上面的接口的定义并不能看出,跟进方法来看所以是一个装饰类。

前面分析SPI机制时,提到createAdaptiveExtensionClass()自动生成和编译一个动态的adpative类。
Compiler的类继承关系:

在Dubbo实现中,默认使用JavassistCompiler进行动态编译,不使用JdKComplier。这一点从Compiler接口的实现中可以看出。

@SPI("javassist")
public interface Compiler {

    /**
     * Compile java source code.
     *
     * @param code        Java source code
     * @param classLoader TODO
     * @return Compiled class
     */
    Class compile(String code, ClassLoader classLoader);
}

可以看到,这里使用了@SPI注解,指定了使用javassist。
回顾前面的调用流程:

-->createAdaptiveExtensionClass()
    -->createAdaptiveExtensionClassCode()
    -->com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
    -->compiler.compile(code, classLoader)
      -->AdaptiveCompiler.compile(code, classLoader)
          -->AbstractCompiler.compile(code, classLoader) 
              -->Class doCompile(String name, String source)
                  -->JavassistCompiler.doCompile(String name, String source) 
                      -->cls.toClass(ClassHelper.getCallerClassLoader(getClass()), JavassistCompiler.class.getProtectionDomain());//编译成class返回

根据前面分析SPI机制时得出的结论:

getExtensionLoader(Class type) 就是为该接口new 一个ExtensionLoader,然后缓存起来。
getAdaptiveExtension() 获取一个扩展类,如果@Adaptive注解在类上就是一个装饰类;如果注解在方法上就是一个动态代理类,例如Protocol$Adaptive对象。
getExtension(String name) 获取一个指定对象。

这里首先为Compiler接口创建了一个ExtensionLoader。然后调用getAdaptiveExtension()获取扩展类。那么这个Compiler是一个装饰类还是一个动态代理类?从上面的Compiler接口的定义并不能看出,跟进compile()方法来看:

@Adaptive
public class AdaptiveCompiler implements Compiler 

所以Compiler是一个装饰类。
接着看createAdaptiveExtensionClass()具体实现:

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

这里会执行到AdaptiveCompiler的实现:

@Adaptive
public class AdaptiveCompiler implements Compiler {

    private static volatile String DEFAULT_COMPILER;

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

    public Class compile(String code, ClassLoader classLoader) {
        Compiler compiler;
        ExtensionLoader loader = ExtensionLoader.getExtensionLoader(Compiler.class);
        String name = DEFAULT_COMPILER; // copy reference
        if (name != null && name.length() > 0) {
            compiler = loader.getExtension(name);
        } else {
            compiler = loader.getDefaultExtension();
        }
        return compiler.compile(code, classLoader);
    }
}

这里DEFAULT_COMPILER执行compile时并未赋值,所以会执行else分支,这里最终会根据@SPI("javassist")获取JavassistCompiler。然后使用其compile()进行编译code,这里会调用到抽象类AbstractCompiler的实现:

public abstract class AbstractCompiler implements Compiler {

    private static final Pattern PACKAGE_PATTERN = Pattern.compile("packages+([$_a-zA-Z][$_a-zA-Z0-9.]*);");

    private static final Pattern CLASS_PATTERN = Pattern.compile("classs+([$_a-zA-Z][$_a-zA-Z0-9]*)s+");

    public Class compile(String code, ClassLoader classLoader) {
        code = code.trim();
        Matcher matcher = PACKAGE_PATTERN.matcher(code);
        String pkg;
        if (matcher.find()) {
            pkg = matcher.group(1);
        } else {
            pkg = "";
        }
        matcher = CLASS_PATTERN.matcher(code);
        String cls;
        if (matcher.find()) {
            cls = matcher.group(1);
        } else {
            throw new IllegalArgumentException("No such class name in " + code);
        }
        String className = pkg != null && pkg.length() > 0 ? pkg + "." + cls : cls;
        try {
            return Class.forName(className, true, ClassHelper.getCallerClassLoader(getClass()));
        } catch (ClassNotFoundException e) {
            if (!code.endsWith("}")) {
                throw new IllegalStateException("The java code not endsWith "}", code: 
" + code + "
");
            }
            try {
                return doCompile(className, code);
            } catch (RuntimeException t) {
                throw t;
            } catch (Throwable t) {
                throw new IllegalStateException("Failed to compile class, cause: " + t.getMessage() + ", class: " + className + ", code: 
" + code + "
, stack: " + ClassUtils.toString(t));
            }
        }
    }

    protected abstract Class doCompile(String name, String source) throws Throwable;

}

在上述代码中首先会去使用类加载器Class.forName去加载目标类,如果类本身(如动态代理类$Adaptive)不存在则会走到异常处理代码,doCompile()这里会调用到JavassistCompiler的具体实现。在该类中最后会返回编译的class:

cls.toClass(ClassHelper.getCallerClassLoader(getClass()), JavassistCompiler.class.getProtectionDomain());

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/68531.html

相关文章

  • 结合Dubbo源码分析Spi

    摘要:如前所说,的目的是获取一个指定实现类的对象。接下来从子模块下的包的开始分析先来看这里继承自类。如没有扩展点,在扩展点实现调用该方法,并返回结果。前面已经分析过,就是使用读取文件并缓存的反转控制,就是从和里面提取对象赋值。 如前所说,Dubbo SPI的目的是获取一个指定实现类的对象。那么Dubbo是通过什么方式获取的呢?其实是调用ExtensionLoader.getExtension...

    tylin 评论0 收藏0
  • dubbo源码解析(二)Dubbo扩展机制SPI

    摘要:二注解该注解为了保证在内部调用具体实现的时候不是硬编码来指定引用哪个实现,也就是为了适配一个接口的多种实现,这样做符合模块接口设计的可插拔原则,也增加了整个框架的灵活性,该注解也实现了扩展点自动装配的特性。 Dubbo扩展机制SPI 前一篇文章《dubbo源码解析(一)Hello,Dubbo》是对dubbo整个项目大体的介绍,而从这篇文章开始,我将会从源码来解读dubbo再各个模块的实...

    DirtyMind 评论0 收藏0
  • dubbo源码解析(二十三)远程调用——Proxy

    摘要:第二种是,是一款字节码引擎工具,能够在运行时编译生成。后记该部分相关的源码解析地址该文章讲解了远程调用中关于代理的部分,关键部分在于基于实现的字节码技术来支撑动态代理。 远程调用——Proxy 目标:介绍远程调用代理的设计和实现,介绍dubbo-rpc-api中的各种proxy包的源码。 前言 首先声明叫做代理,代理在很多领域都存在,最形象的就是现在朋友圈的微商代理,厂家委托代理帮他们...

    Cristic 评论0 收藏0
  • 编译与部署dubbo管控平台dubbo-admin

    摘要:编译完成后在目录下有的包二部署首先将编译后的包放到目录,启动。自动解压包如图是的一个应用服务器。也依赖填写你的服务的部署地址。最后重启,重启之前保证服务处于运行状态。 一.dubbo编译1、先从github上下载dubbo源码,地址:https://github.com/alibaba/du... showImg(https://segmentfault.com/img/bV1fir?...

    Tony 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<