java动态编译
动态编译,顾名思义,就是在jvm运行过程中可以编译运行其他java代码。
亦是通过《编写高质量代码》此书看到的案例,特此记录。
http://yuedu.163.com/book_reader/d050cae1f7cf4137ac28109827cbe90b_4
主要是:
JavaCompiler cmp = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fm = cmp.getStandardFileManager(null, null, null);
JavaCompiler是编译器,用来负责调用任务编译文件;
StandardJavaFileManager 中API解释如下,This file manager creates file objects representing regular files, zip file entries, or entries in similar file system based containers. 为了生成文件而存在的。
JavaFileObject 关于此类查看API解释如下,File abstraction for tools operating on Java™ programming language source and class files.可以看出应该是和需要动态编译的源码以及要生成的class文件有关。
下面是动态编译的一个案例代码
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class Client {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
String sourceStr =
"public class Hello{"
+"public String sayHello(String name){"
+ "return \"Hello,\"+name+\"!\";"
+ "}"
+ "}";
String clsName = "Hello";
String methodName = "sayHello";
JavaCompiler cmp = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fm = cmp.getStandardFileManager(null, null, null);
JavaFileObject jfo = new StringJavaObject(clsName,sourceStr);
List<String> optionsList = new ArrayList<String>();
optionsList.addAll(Arrays.asList("-d","./target/classes"));
List<JavaFileObject> jfos = Arrays.asList(jfo);
JavaCompiler.CompilationTask task = cmp.getTask(null, fm, null, optionsList, null, jfos);
if(task.call()) {
Object obj = Class.forName(clsName).newInstance();
Class<? extends Object> cls = obj.getClass();
Method m = cls.getMethod(methodName, String.class);
String str = (String) m.invoke(obj, "Dynamic Complilation");
System.out.println(str);
}
}
}
其中./target/classes是存放class文件的目录,即编译目录,这是建立的一个maven工程,如图运行后在classes目录生成Hello.class文件
import java.io.IOException;
import java.net.URI;
import javax.tools.SimpleJavaFileObject;
public class StringJavaObject extends SimpleJavaFileObject{
private String content = "";
public StringJavaObject(String _javaFileName,String _content) {
super(_createStringJavaObjectUri(_javaFileName),Kind.SOURCE);
content = _content;
}
private static URI _createStringJavaObjectUri(String name) {
return URI.create("String:///"+name+Kind.SOURCE.extension);
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException{
return content;
}
}
当编译完成,并且成功后就会调用Hello类中的方法,如下代码所示:
if(task.call()) {
Object obj = Class.forName(clsName).newInstance();
Class<? extends Object> cls = obj.getClass();
Method m = cls.getMethod(methodName, String.class);
String str = (String) m.invoke(obj, "Dynamic Complilation");
System.out.println(str);
}