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,Listops){
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");
//设置编译参数
ArrayListops=newArrayList();
ops.add("-Xlint:unchecked");
//编译代码,返回class
Class>cls=ClassUtil.loadClass("/com/even/test/Sum.java",sb.toString(),"com.even.test.Sum",ops);
//准备测试数据
Mapdata=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中的引用和动态代理的实现详解
如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!