当时接到一个活, 需要做程序的评测, 前端传递java代码到后端, 后端进行java代码的评测.
包括java代码是否能够编译运行, 结果是否正确, 程序运行的时间, 以及程序运行占用的内存的.
这个时候我们就需要使用到java的动态编译了. 其实首先想到的就是JavaCompiler 这个类了, 可以自己实现一套代码的编译逻辑,
但是本着尽量做完的原则, 就不自己造轮子了,这里有个选择,
国人, 廖雪峰 他最JavaCompile对了一个简单的封装, 打成了jar包, 可以实现一些比较简单的编译功能. 试了一下还是蛮好用的.
这里就不列举了.
关于java的动态编译, 我们还可以使用asm 或者 javassit, 这次我们的技术选择使用javassit, 因为asm过于复杂, 时间不允许, 暂时也没有业务场景一定要用到asm,就选择了相对简单的javassit了.
下面我们来说下, javassit的简单使用.
首先需要引入jar包:
org.javassist
javassist
3.26.0-GA
package com.onyx.demo;
import javassist.*;
public class Demo{
public static void demo() throws Exception {
ClassPool pool = ClassPool.getDefault();
// 1. 创建一个空类
CtClass cc = pool.makeClass("com.onyx.demo.Person");
// 2. 新增一个字段 private String name;
// 字段名为name
CtField param = new CtField(pool.get("java.lang.String"), "name", cc);
// 访问级别是 private
param.setModifiers(Modifier.PRIVATE);
// 初始值是 "chengcheng"
cc.addField(param, CtField.Initializer.constant("chengcheng"));
// 3. 生成 getter、setter 方法
cc.addMethod(CtNewMethod.setter("setName", param));
cc.addMethod(CtNewMethod.getter("getName", param));
// 4. 添加无参的构造函数
CtConstructor cons = new CtConstructor(new CtClass[]{}, cc);
cons.setBody("{name = \"chengcheng\";}");
cc.addConstructor(cons);
// 5. 添加有参的构造函数
cons = new CtConstructor(new CtClass[]{pool.get("java.lang.String")}, cc);
// $0=this / $1,$2,$3... 代表方法参数
cons.setBody("{$0.name = $1;}");
cc.addConstructor(cons);
// 6. 创建一个名为printName方法,无参数,无返回值,输出name值
CtMethod ctMethod = new CtMethod(CtClass.voidType, "printName", new CtClass[]{}, cc);
ctMethod.setModifiers(Modifier.PUBLIC);
ctMethod.setBody("{System.out.println(name);}");
cc.addMethod(ctMethod);
//这里会将这个创建的类对象编译为.class文件
cc.writeFile("D:/");
}
public static void main(String[] args) {
try {
demo();
} catch (Exception e) {
e.printStackTrace();
}
}
}
好了, 基本的使用. 我也是参照这个写的入门的例子, 就到这里了
如果觉得不够的话, 可以去参考这个, 写的很详细, 我就不继续写了.
https://www.cnblogs.com/rickiyang/p/11336268.html
实际的环境是, 我并不需要产生文件到磁盘上去, 再加载到内存中, 我只需要把java代码的字符串进行编译, 然后运行得到结果就可以了. 具体的.class文件我并不关心.