Java动态编译执行代码示例
程序员文章站
2023-12-15 16:06:52
在某些情况下,我们需要动态生成java代码,通过动态编译,然后执行代码。javaapi提供了相应的工具(javacompiler)来实现动态编译。下面我们通过一个简单的例子...
在某些情况下,我们需要动态生成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动态编译执行代码示例的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:
如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!