Java动态编译执行代码示例

时间:2021-10-08 22:59:11

在某些情况下,我们需要动态生成java代码,通过动态编译,然后执行代码。JAVAAPI提供了相应的工具(JavaCompiler)来实现动态编译。下面我们通过一个简单的例子介绍,如何通过JavaCompiler实现java代码动态编译。

一、获取JavaCompiler

?
1
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

获取JDK提供的java编译器,如果没有提供编译器,则返回null;

二、编译

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//获取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中,否则会编译失败。

三、执行

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//要加载的类名
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);

四、完整代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//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;
    }
}

五、测试

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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);
    }

测试结果

?
1
2
3
4
5
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动态编译执行代码示例的全部内容,希望对大家有所帮助。如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

原文链接:http://blog.csdn.net/zleven/article/details/54094493