动态编译器
Liquor Java 动态编译器。支持完整的 Java 语法及各版本特性(具体看运行时版本)。编译特点:
- 可以指定父类加载器(默认,为当前线程内容类加载器)
- 可以单个类编译
- 可以多个类同时编译
- 可以增量编译
- 非线程安全。多线程时,要注意锁控制。
- 编译的性能,可以按“次”计算。尽量多类编译一次。
编译后,从 ClassLoader 获取类。
1、入门示例
public class DemoApp {
public static void main(String[] args) throws Exception{
//可以复用(可以,不断的增量编译)
DynamicCompiler compiler = new DynamicCompiler();
String className = "HelloWorld";
String classCode = "public class HelloWorld { " +
" public static void helloWorld() { " +
" System.out.println(\"Hello world!\"); " +
" } " +
"}";
//添加源码(可多个)并 构建
compiler.addSource(className, classCode).build();
//构建后,仍可添加不同类的源码再构建
Class<?> clazz = compiler.getClassLoader().loadClass(className);
clazz.getMethod("helloWorld").invoke(null);
}
}
2、多类编译示例
可以把需要编译的代码收集后,多类编译一次。这样,时间更少。
public class DemoApp {
@Test
public void test() throws Exception{
DynamicCompiler compiler = new DynamicCompiler();
compiler.addSource("com.demo.UserDo", "package com.demo;\n" +
"import java.util.HashMap;\n\n"+
"public class UserDo{\n" +
" private String name;\n" +
"\n" +
" public String getName() {\n" +
" return name;\n" +
" }\n" +
" \n" +
" public UserDo(String name) {\n" +
" this.name = name;\n" +
" }\n" +
"}");
compiler.addSource("com.demo.IUserService", "package com.demo;\n" +
"public interface IUserService {\n" +
" UserDo getUser(String name);\n" +
"}");
compiler.addSource("com.demo.UserService", "package com.demo;\n" +
"public class UserService implements IUserService {\n" +
" @Override\n" +
" public UserDo getUser(String name) {\n" +
" return new UserDo(name);\n" +
" }\n" +
"}");
compiler.build();
Class<?> clz = compiler.getClassLoader().loadClass("com.demo.UserService");
Object obj = clz.newInstance();
System.out.println(obj);
System.out.println(obj.getClass());
Object objUser = clz.getMethods()[0].invoke(obj, "noear");
System.out.println(objUser);
System.out.println(objUser.getClass());
}
}
3、类加载器的切换
类加载器 ClassLoader 内部是基于 hash 管理类的,所以相同的类名只能有一个。。。如果我们需要对相同的类名进行编译。可以采用两种方式:
- 重新实例化动态编译器(DynamicCompiler)
- 通过切换类加载器(也可以新建类加载器)。应用时,可建立识别体系,识别是重要换新的类加载器?
ClassLoader cl_old = compiler.getClassLoader();
ClassLoader cl_new = compiler.newClassLoader();
compiler.setClassLoader(cl_new);
compiler.addSource("...");
compiler.build();
//...用完,可以换回来 //只是示例
compiler.setClassLoader(cl_old);