2.4 Dubbo的动态编译原理
众所周知,Java程序要想运行首先需要使用javac把源代码编译为class字节码文件,然后使用JVM把class字节码文件加载到内存创建Class对象后,使用Class对象创建对象实例。正常情况下我们是把所有源文件静态编译为字节码文件,然后由JVM统一加载,而动态编译则是在JVM进程运行时把源文件编译为字节码文件,然后使用字节码文件创建对象实例。
上一节我们提到,在Dubbo框架中框架会给每个SPI扩展接口动态生成一个对应的适配器类,那么如何生成呢?这里就使用了动态编译技术,在Dubbo中提供了一个Compiler的SPI:
Dubbo提供Compiler的实现有JavassistCompiler(默认实现)和JdkCompiler两种。
这里我们从Dubbo框架如何使用动态编译生成扩展接口对应的适配器类入手,首先我们打开ExtensionLoader的createAdaptiveExtensionClass()方法,就是该方法将源文件动态编译为Class对象的,有了Class对象后,我们就可以使用newInstance()方法创建对象实例了:
代码1是根据SPI扩展接口生成其对应的适配器类的源码,其返回的是一个字符串,比如对于Protocol扩展接口来说,返回的字符串内容为:
代码2使用增强SPI选择扩展接口Compiler的实现,这里默认为JavassistCompiler,然后代码3调用JavassistCompiler的compile()方法并根据源代码生成Protocol$Adaptive的Class对象。
总结一下就是,Dubbo框架会为每个扩展接口生成其对应的适配器类的源码,然后选择具体的动态编译类的扩展实现对源码进行编译以生成适配器类的Class对象,然后就可以调用Class对象的newInstance()方法生成扩展接口对应的适配器类的实例。