首页 > 开发 > Java > 正文

Java动态编译执行代码示例

2024-07-13 10:15:10
字体:
来源:转载
供稿:网友

在某些情况下,我们需要动态生成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");//设置classpathops.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.javaimport 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.java16:12:03.544 DEBUG com.even.tools.ClassUtil - Compile Java File:.../classes//com/even/test/Sum.java16:12:03.545 DEBUG com.even.tools.ClassUtil - Load Class[com.even.test.Sum] by sun.misc.Launcher$AppClassLoader@73d16e9316: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教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表