当前位置: 移动技术网 > IT编程>开发语言>Java > Java动态编译执行代码示例

Java动态编译执行代码示例

2019年07月19日  | 移动技术网IT编程  | 我要评论

在某些情况下,我们需要动态生成java代码,通过动态编译,然后执行代码。javaapi提供了相应的工具(javacompiler)来实现动态编译。下面我们通过一个简单的例子介绍,如何通过javacompiler实现java代码动态编译。

一、获取javacompiler

javacompiler compiler = toolprovider.getsystemjavacompiler();

获取jdk提供的java编译器,如果没有提供编译器,则返回null;

二、编译

//获取java文件管理类
standardjavafilemanager manager = compiler.getstandardfilemanager(null, null, null);
//获取java文件对象迭代器
iterable<? extends javafileobject> it = manager.getjavafileobjects(files);
//设置编译参数
arraylist<string> ops = new arraylist<string>();
ops.add("-xlint:unchecked");
//设置classpath
ops.add("-classpath");
ops.add(class_path);
//获取编译任务
javacompiler.compilationtask task = compiler.gettask(null, manager, null, ops, null, it);
//执行编译任务
task.call();

当我们要编译的源代码中,引用了其他代码,我们需要将引用代码路径设置到-classpath中,否则会编译失败。

三、执行

//要加载的类名
string classname = "xxx.xxx.xxx";
//获取类加载器
classloader classloader = xxx.class.getclassloader();
//加载类
class<?> cls = classloader.loadclass(classname);

//调用方法名称
string methodname = "execute";
//方法参数类型数组
class<?>[] paramcls = {...};
//获取方法
method method = cls.getdeclaredmethod(methodname , paramcls);
//创建类实例
object obj = cls.newinstance();
//方法参数
object[] params = {...};
//调用方法
object result = method.invoke(obj, params);

四、完整代码

//classutil.java
import java.io.filewriter;
import java.io.bufferedwriter;
import java.io.file;
import java.io.ioexception;
import java.util.arraylist;
import javax.tools.javacompiler;
import javax.tools.toolprovider;
import javax.tools.javafileobject;
import javax.tools.standardjavafilemanager;
import org.apache.commons.logging.log;
import org.apache.commons.logging.logfactory;
public class classutil {
	private static final log logger = logfactory.getlog(classutil.class);
	private static javacompiler compiler;
	static{
		compiler = toolprovider.getsystemjavacompiler();
	}
	/**
   * 获取java文件路径
   * @param file
   * @return
   */
	private static string getfilepath(string file){
		int last1 = file.lastindexof('/');
		int last2 = file.lastindexof('\\');
		return file.substring(0, last1>last2?last1:last2)+file.separatorchar;
	}
	/**
   * 编译java文件
   * @param ops 编译参数
   * @param files 编译文件
   */
	private static void javac(list<string> ops,string... files){
		standardjavafilemanager manager = null;
		try{
			manager = compiler.getstandardfilemanager(null, null, null);
			iterable<? extends javafileobject> it = manager.getjavafileobjects(files);
			javacompiler.compilationtask task = compiler.gettask(null, manager, null, ops, null, it);
			task.call();
			if(logger.isdebugenabled()){
				for (string file:files)
				          logger.debug("compile java file:" + file);
			}
		}
		catch(exception e){
			logger.error(e);
		}
		finally{
			if(manager!=null){
				try {
					manager.close();
				}
				catch (ioexception e) {
					e.printstacktrace();
				}
			}
		}
	}
	/**
   * 生成java文件
   * @param file 文件名
   * @param source java代码
   * @throws exception
   */
	private static void writejavafile(string file,string source)throws exception{
		if(logger.isdebugenabled()){
			logger.debug("write java source code to:"+file);
		}
		bufferedwriter bw = null;
		try{
			file dir = new file(getfilepath(file));
			if(!dir.exists())
			        dir.mkdirs();
			bw = new bufferedwriter(new filewriter(file));
			bw.write(source);
			bw.flush();
		}
		catch(exception e){
			throw e;
		}
		finally{
			if(bw!=null){
				bw.close();
			}
		}
	}
	/**
   * 加载类
   * @param name 类名
   * @return
   */
	private static class<?> load(string name){
		class<?> cls = null;
		classloader classloader = null;
		try{
			classloader = classutil.class.getclassloader();
			cls = classloader.loadclass(name);
			if(logger.isdebugenabled()){
				logger.debug("load class["+name+"] by "+classloader);
			}
		}
		catch(exception e){
			logger.error(e);
		}
		return cls;
	}
	/**
   * 编译代码并加载类
   * @param filepath java代码路径
   * @param source java代码
   * @param clsname 类名
   * @param ops 编译参数
   * @return
   */
	public static class<?> loadclass(string filepath,string source,string clsname,list<string> ops){
		try {
			writejavafile(class_path+filepath,source);
			javac(ops,class_path+filepath);
			return load(clsname);
		}
		catch (exception e) {
			logger.error(e);
		}
		return null;
	}
	/**
   * 调用类方法
   * @param cls 类
   * @param methodname 方法名
   * @param paramscls 方法参数类型
   * @param params 方法参数
   * @return
   */
	public static object invoke(class<?> cls,string methodname,class<?>[] paramscls,object[] params){
		object result = null;
		try {
			method method = cls.getdeclaredmethod(methodname, paramscls);
			object obj = cls.newinstance();
			result = method.invoke(obj, params);
		}
		catch (exception e) {
			logger.error(e);
		}
		return result;
	}
}

五、测试

public class classutiltest {
	private static final log logger = logfactory.getlog(classutiltest.class);
	public static void main(string args[]){
		stringbuilder sb = new stringbuilder();
		sb.append("package com.even.test;");
		sb.append("import java.util.map;\nimport java.text.decimalformat;\n");
		sb.append("public class sum{\n");
		sb.append("private final decimalformat df = new decimalformat(\"#.#####\");\n");
		sb.append("public double calculate(map<string,double> data){\n");
		sb.append("double d = (30*data.get(\"f1\") + 20*data.get(\"f2\") + 50*data.get(\"f3\"))/100;\n");
		sb.append("return double.valueof(df.format(d));}}\n");
		//设置编译参数
		arraylist<string> ops = new arraylist<string>();
		ops.add("-xlint:unchecked");
		//编译代码,返回class
		class<?> cls = classutil.loadclass("/com/even/test/sum.java",sb.tostring(),"com.even.test.sum",ops);
		//准备测试数据
		map<string,double> data = new hashmap<string,double>();
		data.put("f1", 10.0);
		data.put("f2", 20.0);
		data.put("f3", 30.0);
		//执行测试方法
		object result = classutil.invoke(cls, "calculate", new class[]{map.class}, new object[]{data});
		//输出结果
		logger.debug(data);
		logger.debug("(30*f1+20*f2+50*f3)/100 = "+result);
	}

测试结果

16:12:02.860 debug com.even.tools.classutil - write java source code to: .../classes//com/even/test/sum.java
16:12:03.544 debug com.even.tools.classutil - compile java file:.../classes//com/even/test/sum.java
16:12:03.545 debug com.even.tools.classutil - load class[com.even.test.sum] by sun.misc.launcher$appclassloader@73d16e93
16:12:03.547 debug com.even.test.classutiltest - {f1=10.0, f2=20.0, f3=30.0}
16:12:03.547 debug com.even.test.classutiltest - (30*f1+20*f2+50*f3)/100 = 22.0

总结

以上就是本文关于java动态编译执行代码示例的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:

java动态规划之编辑距离问题示例代码

java中的引用和动态代理的实现详解

如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网