在某些情況下,我們需要動態生成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