Java的动态生成编译库

发表于2020-02-10,长度1497, 183个单词, 4分钟读完
Flag Counter

从 JDK 1.6 开始java 引入了用 Java 代码重写的编译器接口,使得我们可以在运行时编译 Java 源码,然后用类加载器进行加载,让 Java 语言更具灵活性,能够完成许多高级的操作。不过,我们最期望的还是给定一段代码,直接编译,然后运行,也就是空中编译执行(on-the-fly)。

下面我用几种方法实现动态生成和执行如下面的类的方法sum():

public class Model {
    private int a, b;

    public Model(int a, int b) {
        this.a = a;
        this.b = b;
    }

    public int sum() {
        return a + b;
    }
}

本文的代码都上传到了 https://github.com/davelet/dynamic-java

javassist

这一个就不说了,直接看代码吧:https://github.com/davelet/dynamic-java/tree/master/javassist-compile

javassist 应该是我们最早接触的一个动态编译框架,它和asm(下面就是这个)都是字节码解析和生成工具。这里只说到了它的生成能力,解析能力可以自行百度。

ASM

如上面所提,也直接看代码吧:https://github.com/davelet/dynamic-java/tree/master/asm-compile

asm的生成比javassist复杂,要求我们对字节码的解释过程比较熟悉才行。所以对比javassist,asm更极客一点。

JOOR

这是github上一个开源库,用于方便的编译给定源代码的。参考代码:https://github.com/davelet/dynamic-java/tree/master/joor-lib。就是把源代码写好进行编译。

除了给定一串可编译的源码进行编译外,joor还提供了更灵活的操作能力。比如:

String world = on("java.lang.String")
        .create("Hello World")
        .call("substring", 6)
        .call("toString")
        .get();
System.out.println(world);

这段代码的意思是先创建一个字符串,再对它执行substr操作。


JavaPoet

这个不是编译库,这个是用于生成Java源代码的。生成以后可以使用jdk或者joor进行编译执行。简单参考:https://github.com/davelet/dynamic-java/tree/master/javapoet-lib

注意

在使用动态编译时,需要注意以下几点:

(1)谨慎使用

debug很困难;

(2)不要在要求高性能的项目使用

动态编译毕竟需要一个编译过程,与静态编译相比多了一个执行环节,因此在高性能项目中不要使用动态编译。

(3)动态编译要考虑安全问题

如果你在Web界面上提供了一个功能,允许上传一个Java文件然后运行,那就等于说:“我的机器没有密码,大家都来看我的隐私吧”,这是非常典型的注入漏洞,只要上传一个恶意Java程序就可以让你所有的安全工作毁于一旦。

(4)记录动态编译过程

建议记录源文件、目标文件、编译过程、执行过程等日志,不仅仅是为了诊断,还是为了安全和审计,对Java项目来说,空中编译和运行是很不让人放心的,留下这些依据可以更好地优化程序。

Written on February 10, 2020
分类: dev, 标签: java database
如果你喜欢,请赞赏! davelet