Java动态编译执行代码示例
在某些情况下,我们需要动态生成java代码,通过动态编译,然后执行代码。JAVAAPI提供了相应的工具(JavaCompiler)来实现动态编译。下面我们通过一个简单的例子介绍,如何通过JavaCompiler实现java代码动态编译。
一、获取JavaCompiler
JavaCompilercompiler=ToolProvider.getSystemJavaCompiler();
获取JDK提供的java编译器,如果没有提供编译器,则返回null;
二、编译
//获取java文件管理类 StandardJavaFileManagermanager=compiler.getStandardFileManager(null,null,null); //获取java文件对象迭代器 Iterableit=manager.getJavaFileObjects(files); //设置编译参数 ArrayListops=newArrayList (); ops.add("-Xlint:unchecked"); //设置classpath ops.add("-classpath"); ops.add(CLASS_PATH); //获取编译任务 JavaCompiler.CompilationTasktask=compiler.getTask(null,manager,null,ops,null,it); //执行编译任务 task.call();
当我们要编译的源代码中,引用了其他代码,我们需要将引用代码路径设置到-classpath中,否则会编译失败。
三、执行
//要加载的类名 StringclassName="xxx.xxx.xxx"; //获取类加载器 ClassLoaderclassLoader=XXX.class.getClassLoader(); //加载类 Class>cls=classLoader.loadClass(className); //调用方法名称 StringmethodName="execute"; //方法参数类型数组 Class>[]paramCls={...}; //获取方法 Methodmethod=cls.getDeclaredMethod(methodName,paramCls); //创建类实例 Objectobj=cls.newInstance(); //方法参数 Object[]params={...}; //调用方法 Objectresult=method.invoke(obj,params);
四、完整代码
//ClassUtil.java importjava.io.FileWriter; importjava.io.BufferedWriter; importjava.io.File; importjava.io.IOException; importjava.util.ArrayList; importjavax.tools.JavaCompiler; importjavax.tools.ToolProvider; importjavax.tools.JavaFileObject; importjavax.tools.StandardJavaFileManager; importorg.apache.commons.logging.Log; importorg.apache.commons.logging.LogFactory; publicclassClassUtil{ privatestaticfinalLoglogger=LogFactory.getLog(ClassUtil.class); privatestaticJavaCompilercompiler; static{ compiler=ToolProvider.getSystemJavaCompiler(); } /** *获取java文件路径 *@paramfile *@return */ privatestaticStringgetFilePath(Stringfile){ intlast1=file.lastIndexOf('/'); intlast2=file.lastIndexOf('\\'); returnfile.substring(0,last1>last2?last1:last2)+File.separatorchar; } /** *编译java文件 *@paramops编译参数 *@paramfiles编译文件 */ privatestaticvoidjavac(Listops,String...files){ StandardJavaFileManagermanager=null; try{ manager=compiler.getStandardFileManager(null,null,null); Iterableit=manager.getJavaFileObjects(files); JavaCompiler.CompilationTasktask=compiler.getTask(null,manager,null,ops,null,it); task.call(); if(logger.isDebugEnabled()){ for(Stringfile:files) logger.debug("CompileJavaFile:"+file); } } catch(Exceptione){ logger.error(e); } finally{ if(manager!=null){ try{ manager.close(); } catch(IOExceptione){ e.printStackTrace(); } } } } /** *生成java文件 *@paramfile文件名 *@paramsourcejava代码 *@throwsException */ privatestaticvoidwriteJavaFile(Stringfile,Stringsource)throwsException{ if(logger.isDebugEnabled()){ logger.debug("WriteJavaSourceCodeto:"+file); } BufferedWriterbw=null; try{ Filedir=newFile(getFilePath(file)); if(!dir.exists()) dir.mkdirs(); bw=newBufferedWriter(newFileWriter(file)); bw.write(source); bw.flush(); } catch(Exceptione){ throwe; } finally{ if(bw!=null){ bw.close(); } } } /** *加载类 *@paramname类名 *@return */ privatestaticClass>load(Stringname){ Class>cls=null; ClassLoaderclassLoader=null; try{ classLoader=ClassUtil.class.getClassLoader(); cls=classLoader.loadClass(name); if(logger.isDebugEnabled()){ logger.debug("LoadClass["+name+"]by"+classLoader); } } catch(Exceptione){ logger.error(e); } returncls; } /** *编译代码并加载类 *@paramfilePathjava代码路径 *@paramsourcejava代码 *@paramclsName类名 *@paramops编译参数 *@return */ publicstaticClass>loadClass(StringfilePath,Stringsource,StringclsName,List ops){ try{ writeJavaFile(CLASS_PATH+filePath,source); javac(ops,CLASS_PATH+filePath); returnload(clsName); } catch(Exceptione){ logger.error(e); } returnnull; } /** *调用类方法 *@paramcls类 *@parammethodName方法名 *@paramparamsCls方法参数类型 *@paramparams方法参数 *@return */ publicstaticObjectinvoke(Class>cls,StringmethodName,Class>[]paramsCls,Object[]params){ Objectresult=null; try{ Methodmethod=cls.getDeclaredMethod(methodName,paramsCls); Objectobj=cls.newInstance(); result=method.invoke(obj,params); } catch(Exceptione){ logger.error(e); } returnresult; } }
五、测试
publicclassClassUtilTest{ privatestaticfinalLoglogger=LogFactory.getLog(ClassUtilTest.class); publicstaticvoidmain(Stringargs[]){ StringBuildersb=newStringBuilder(); sb.append("packagecom.even.test;"); sb.append("importjava.util.Map;\nimportjava.text.DecimalFormat;\n"); sb.append("publicclassSum{\n"); sb.append("privatefinalDecimalFormatdf=newDecimalFormat(\"#.#####\");\n"); sb.append("publicDoublecalculate(Mapdata){\n"); sb.append("doubled=(30*data.get(\"f1\")+20*data.get(\"f2\")+50*data.get(\"f3\"))/100;\n"); sb.append("returnDouble.valueOf(df.format(d));}}\n"); //设置编译参数 ArrayList ops=newArrayList (); ops.add("-Xlint:unchecked"); //编译代码,返回class Class>cls=ClassUtil.loadClass("/com/even/test/Sum.java",sb.toString(),"com.even.test.Sum",ops); //准备测试数据 Map data=newHashMap (); data.put("f1",10.0); data.put("f2",20.0); data.put("f3",30.0); //执行测试方法 Objectresult=ClassUtil.invoke(cls,"calculate",newClass[]{Map.class},newObject[]{data}); //输出结果 logger.debug(data); logger.debug("(30*f1+20*f2+50*f3)/100="+result); }
测试结果
16:12:02.860DEBUGcom.even.tools.ClassUtil-WriteJavaSourceCodeto:.../classes//com/even/test/Sum.java 16:12:03.544DEBUGcom.even.tools.ClassUtil-CompileJavaFile:.../classes//com/even/test/Sum.java 16:12:03.545DEBUGcom.even.tools.ClassUtil-LoadClass[com.even.test.Sum]bysun.misc.Launcher$AppClassLoader@73d16e93 16:12:03.547DEBUGcom.even.test.ClassUtilTest-{f1=10.0,f2=20.0,f3=30.0} 16:12:03.547DEBUGcom.even.test.ClassUtilTest-(30*f1+20*f2+50*f3)/100=22.0
总结
以上就是本文关于Java动态编译执行代码示例的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:
java编程进行动态编译加载代码分享
Java动态规划之编辑距离问题示例代码
Java中的引用和动态代理的实现详解
如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!