现在我们可以用
JDK6
的
Compiler API(JSR 199)
去动态编译
Java
源文件,
Compiler API
结合反射功能就可以实现动态的产生
Java
代码并编译执行这些代码,有点动态语言的特征。这个特性对于某些需要用到动态编译的应用程序相当有用,
比如
JSP Web Server
,当我们手动修改
JSP
后,是不希望需要重启
Web Server
才可以看到效果的,这时候我们就可以用
Compiler API
来实现动态编译
JSP
文件,当然,现在的
JSP Web Server
也是支持
JSP
热部署的,现在的
JSP Web Server
通过在运行期间通过
Runtime.exec
或
ProcessBuilder
来调用
javac
来编译代码,这种方式需要我们产生另一个进程去做编译工作,不够优雅而且容易使代码依赖与特定的操作系统;
Compiler API
通过一套易用的标准的
API
提供了更加丰富的方式去做动态编译
,
而且是跨平台的。
下面代码演示了
Compiler API
的使用
public class CompilerAPITester {
private static String JAVA_SOURCE_FILE = "DynamicObject.java";
private static String JAVA_CLASS_FILE = "DynamicObject.class";
private static String JAVA_CLASS_NAME = "DynamicObject";
public static void main(String[] args) {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
generateJavaClass();
try {
//
将产生的类文件拷贝到程序的
ClassPath
下面
,
下面这一行代码是特定于
Windows
+
IntelliJ IDEA 6.0
项目
,
不具有移植性
Runtime.getRuntime().exec("cmd /c copy "+JAVA_CLASS_FILE+" classes//production//JDK6Features");
Iterable<? extends JavaFileObject> sourcefiles = fileManager.getJavaFileObjects(JAVA_SOURCE_FILE);
compiler.getTask(null, fileManager, null, null, null, sourcefiles).call();
fileManager.close();
Class.forName(JAVA_CLASS_NAME).newInstance();//
创建动态编译得到的
DynamicObject
类的实例
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void generateJavaClass(){
try {
FileWriter fw = new FileWriter(JAVA_SOURCE_FILE);
BufferedWriter bw = new BufferedWriter(fw);
bw.write("public class "+JAVA_CLASS_NAME+"{");
bw.newLine();
bw.write("public "+JAVA_CLASS_NAME+"(){System.out.println(/"In the constructor of DynamicObject/");}}");
bw.flush();
bw.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}