Java动态编译执行代码示例
时间:2020-12-23 13:06:42|栏目:JAVA代码|点击: 次
在某些情况下,我们需要动态生成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动态编译执行代码示例的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:
如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!
阅读排行
- 1Java Swing组件BoxLayout布局用法示例
- 2java中-jar 与nohup的对比
- 3Java邮件发送程序(可以同时发给多个地址、可以带附件)
- 4Caused by: java.lang.ClassNotFoundException: org.objectweb.asm.Type异常
- 5Java中自定义异常详解及实例代码
- 6深入理解Java中的克隆
- 7java读取excel文件的两种方法
- 8解析SpringSecurity+JWT认证流程实现
- 9spring boot里增加表单验证hibernate-validator并在freemarker模板里显示错误信息(推荐)
- 10深入解析java虚拟机