GeXiangDong

精通Java、SQL、Spring的拼写,擅长Linux、Windows的开关机

0%

Java动态编译并通过反射执行

Java 动态编译源码,并通过反射执行编译后的代码的例子。

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
import java.io.File;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;

public class DynamicCompiler{

/**
* 动态编译传入的类源码并返回编译好的类
*/
public Class compile(String sourceCode) throws Exception{
File distDir = new File("target");
if (!distDir.exists()) {
distDir.mkdirs();
}
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
String className = getFullClassNameFromCode(sourceCode);
JavaFileObject javaFileObject = new CodeJavaFileObject(className, sourceCode);
JavaCompiler.CompilationTask task = compiler.getTask(null, null, null,
Arrays.asList("-d", distDir.getAbsolutePath()), null,
Arrays.asList(javaFileObject));
boolean compileSuccess = task.call();
if (!compileSuccess) {
System.out.println("compile failed");
return null;
} else {
//动态执行 (反射执行)
System.out.println("compile successed " + distDir.getAbsolutePath());
//URL 需要以 file:// 开始; 如果是目录需要以 / 结束;也可以是jar
URL[] urls = new URL[] {new URL("file://" + distDir.getAbsolutePath() + "/")};
URLClassLoader classLoader = new URLClassLoader(urls);
Class dynamicClass = classLoader.loadClass(className);
return dynamicClass;
}
}


class CodeJavaFileObject extends SimpleJavaFileObject{
private String code;

public CodeJavaFileObject(String className, String code){
super(URI.create(className.replaceAll("\\.", "/") + Kind.SOURCE.extension), Kind.SOURCE);
this.code = code;
}

@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return code;
}
}

private String getFullClassNameFromCode(String code){
String t = code.substring(0, code.indexOf('{'));
String s = t.replaceAll("[\r\n\t]", " ").trim();
String[] ary = s.split("[;]");
String packageName = null;
String className = getLastPart((ary[ary.length - 1]));
if(ary[0].startsWith("package ")){
packageName = getLastPart(ary[0]);
return packageName + "." + className;
}else{
return className;
}
}

private String getLastPart(String s){
String[] ary = s.trim().split(" ");
return ary[ary.length - 1];
}

public static void main(String[] argvs) throws Exception{
StringBuffer buf = new StringBuffer();
buf.append("package a.b.c;\r\npublic class ANumber{")
.append("public int getNumber() {")
.append("System.out.println(\"Hello World in getNumber()!\"); return 999;")
.append("}")
.append("}");

DynamicCompiler dc = new DynamicCompiler();
Class cls = dc.compile(buf.toString());
System.out.println(cls.getName());
Object obj = cls.getDeclaredConstructor().newInstance();
Method method = cls.getDeclaredMethod("getNumber");
Object r = method.invoke(obj);
System.out.println("result is " + r);
}
}