JAVA动态编译

最近由于要写一个软件度量的工具,里面要用到动态编译JAVA文件,所以就学习了一下JAVA的动态编译机制。

在JAVA的工具包中有ToolProvider可以获得系统的编译器,然后根据相关接口对文件进行动态的编译,不多说了先上代码:

import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;


public class DynamicCompiler {
	
	public static void main(String[] args) throws Exception {
		//获取java系统编译器
		JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
		/**
		 * 获取文件管理器(管理需要编译的文件)
		 * 三个参数详见API文档
		 */
		StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
		//可以根据需要填写多个参数,返回多个文件一块编译
		Iterable it = fileMgr.getJavaFileObjects("D:/DynamicModel.java");
		/**
		 * 获取编译任务
		 * 参数说明详见API文档
		 */
		CompilationTask task = compiler.getTask(null, fileMgr, null, null, null, it);
		//编译java文件然后关闭文件管理器
		task.call();
		fileMgr.close();
		
		/**
		 * 将class文件加载入内存,以供使用
		 * URL固定格式,如果是本地文件需以"file:/"开头
		 * URL参数用于指明class文件的根目录(不包含包名目录)
		 * loadClass的时候需要写上类的完整包名
		 */
		URL[] urls = new URL[]{new URL("file:/"+"D:/")};
		URLClassLoader loader = new URLClassLoader(urls);
		Class cl =loader.loadClass("DynamicModel");
		
		DynamicModel dm =(DynamicModel)cl.newInstance();
		dm.methodA();
		dm.hello("World");
	}
	
	
}

动态编译所需的JAVA文件如下(需要放置在D:/根目录下):

public class DynamicModel {
	public void methodA() {
		System.out.println("I am methodA");
	}
	
	public void hello(String str) {
		System.out.println("Hello " + str);
	}
}

说明:各个接口以及函数的调用可以参考API文档,里面有详细的说明,这里简单的说明几点。

(1) Iterable it = fileMgr.getJavaFileObjects("D:/DynamicModel.java");这里参数可以填写多个,虚拟机会把你所填入的所有文件返回给你,这样的话就可以一次性编译N个文件,可以减少开销。CompilationTask task = compiler.getTask(null, fileMgr, null, null, null, it);这里的详细调用参考API文档,第4个参数是Iterable类型的,指定编译文件所使用的参数,例如"-d d:/temp"指定生成的class文件保存在D/temp目录下,如果没有指定class文件保存的目录,默认保存在.java文件的同等目录下。

(2) 加载class文件的时候 需要使用URLClassLoader不能使用ClassLoader,因为ClassLoader只能加载在classpath下class文件,否则会抛出ClassNotFoundException;在创建URLClassLoader的时候需要指定class文件的根目录,这个目录不应该包含class文件的包名。例如下面的目录结构:

JAVA动态编译_第1张图片

这是eclipse建立JAVA项目的常规目录结构,class文件放置在bin目录下,下面的com/XX/XX/XX...是包名所产生的目录,在指定URLClassLoader目录的时候只能指定"D:/cocomo/bin/"到此为止!注意最后的一个"/"一定要加上否则会报错,找不到class文件。然后loadClass()的时候就要填写要load的是哪个class,这时候要指定class的包名,即加上"com.xx.xx.DynamicMode",这里一定要注意要用写class的完整路径的时候一定要用".",而不是“/”,否则也找不到要load的Class文件。load出来之后就可以使用虚拟机提供给你的类了。

运行结果如下:

JAVA动态编译_第2张图片


你可能感兴趣的:(java,ClassLoader,null,Class,文档,文件管理器)