Java动态编译执行代码示例

网友投稿 455 2023-03-04


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 ops = new ArrayList();

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('\\');

rFqEWNqyvtYeturn file.substring(0, last1>last2?last1:last2)+File.separatorchar;

}

/**

* 编译java文件

* @param ops 编译参数

* @param files 编译文件

*/

private static void javac(List 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 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 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 ops = new ArrayList();

ops.add("-Xlint:unchecked");

//编译代码,返回class

Class> cls = ClassUtil.loadClass("/com/even/test/Sum.java",sb.toString(),"com.even.test.Sum",ops);

//准备测试数据

Map data = new HashMap();

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动态编译执行代码示例的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:

java编程进行动态编译加载代码分享

Java动态规划之编辑距离问题示例代码

Java中的引用和动态代理的实现详解

如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:接口文档设计(接口文档设计教程)
下一篇:vue中使用refs定位dom出现undefined的解决方法
相关文章

 发表评论

暂时没有评论,来抢沙发吧~