java 反射 动态代码_动态编译Java代码并反射运行

1 public classCustomJavaCompiler {2 //源码

3 privateString sourceCode;4 //类全名

5 privateString fullClassName;6 //获取java的编译器

7 private JavaCompiler compiler =ToolProvider.getSystemJavaCompiler();8 //存放编译之后的字节码(key:类全名,value:编译之后输出的字节码)

9 private Map javaFileObjectMap = new ConcurrentHashMap<>();10 //存放编译过程中输出的信息

11 private DiagnosticCollector diagnosticsCollector = new DiagnosticCollector<>();12 //编译耗时(单位ms)

13 private longcompilerTime;14

15 publicCustomJavaCompiler(String sourceCode) {16 this.sourceCode =sourceCode;17 this.fullClassName =getFullClassName(sourceCode);18 }19

20 /**

21 * 编译字符串源代码,编译失败在 diagnosticsCollector 中获取提示信息22 *23 *@returntrue:编译成功 false:编译失败24 */

25 public booleancompiler() {26 if(compiler == null)27 return false;28

29 long startTime =System.currentTimeMillis();30 //标准的内容管理器,更换成自己的实现,覆盖部分方法

31 StandardJavaFileManager standardFileManager = compiler.getStandardFileManager(diagnosticsCollector, null, null);32 JavaFileManager javaFileManager = newStringJavaFileManage(standardFileManager);33 //构造源代码对象

34 JavaFileObject javaFileObject = newStringJavaFileObject(fullClassName, sourceCode);35 //获取一个编译任务

36 JavaCompiler.CompilationTask task = compiler.getTask(null, javaFileManager, diagnosticsCollector, null, null, Arrays.asList(javaFileObject));37 //设置编译耗时

38 compilerTime = System.currentTimeMillis() -startTime;39 returntask.call();40 }41

42 /**

43 * 获取编译后的Class44 *@return

45 */

46 public Class>getCompilerClass() {47 StringClassLoader scl = newStringClassLoader();48 Class> clz = null;49 try{50 clz =scl.findClass(fullClassName);51 } catch(Exception e) {52 e.printStackTrace();53 }54 returnclz;55 }56

57 /**

58 * 获取编译时产生的信息59 *@return编译信息(错误 警告)60 */

61 publicString getCompilerMessage() {62 if(compiler == null)63 return "JRE环境未配置(请复制JDK路径下lib目录内的tools.jar到JRE路径下lib目录里)";64

65 StringBuilder sb = newStringBuilder();66 List> diagnostics =diagnosticsCollector.getDiagnostics();67 for(Diagnostic diagnostic : diagnostics) {68 sb.append(diagnostic.toString()).append("\r\n");69 }70 returnsb.toString();71 }72

73 public longgetCompilerTime() {74 returncompilerTime;75 }76

77 /**

78 * 获取类的全名称79 *@paramsourceCode 源码80 *@return类的全名称81 */

82 public staticString getFullClassName(String sourceCode) {83 String className = "";84 Pattern pattern = Pattern.compile("package\\s+\\S+\\s*;");85 Matcher matcher =pattern.matcher(sourceCode);86 if(matcher.find()) {87 className = matcher.group().replaceFirst("package", "").replace(";", "").trim() + ".";88 }89

90 pattern = Pattern.compile("class\\s+\\S+\\s+\\{");91 matcher =pattern.matcher(sourceCode);92 if(matcher.find()) {93 className += matcher.group().replaceFirst("class", "").replace("{", "").trim();94 }95 returnclassName;96 }97

98 /**

99 * 自定义一个字符串的源码对象100 */

101 private class StringJavaFileObject extendsSimpleJavaFileObject {102 //等待编译的源码字段

103 privateString contents;104

105 //java源代码 => StringJavaFileObject对象 的时候使用

106 publicStringJavaFileObject(String className, String contents) {107 super(URI.create("string:///" + className.replaceAll("\\.", "/") +Kind.SOURCE.extension), Kind.SOURCE);108 this.contents =contents;109 }110

111 //字符串源码会调用该方法

112 @Override113 public CharSequence getCharContent(boolean ignoreEncodingErrors) throwsIOException {114 returncontents;115 }116

117 }118

119 /**

120 * 自定义一个编译之后的字节码对象121 */

122 private class ByteJavaFileObject extendsSimpleJavaFileObject {123 //存放编译后的字节码

124 privateByteArrayOutputStream outPutStream;125

126 publicByteJavaFileObject(String className, Kind kind) {127 super(URI.create("string:///" + className.replaceAll("\\.", "/") +Kind.SOURCE.extension), kind);128 }129

130 //StringJavaFileManage 编译之后的字节码输出会调用该方法(把字节码输出到outputStream)

131 @Override132 publicOutputStream openOutputStream() {133 outPutStream = newByteArrayOutputStream();134 returnoutPutStream;135 }136

137 //在类加载器加载的时候需要用到

138 public byte[] getCompiledBytes() {139 returnoutPutStream.toByteArray();140 }141 }142

143 /**

144 * 自定义一个JavaFileManage来控制编译之后字节码的输出位置145 */

146 private class StringJavaFileManage extendsForwardingJavaFileManager {147 StringJavaFileManage(JavaFileManager fileManager) {148 super(fileManager);149 }150

151 //获取输出的文件对象,它表示给定位置处指定类型的指定类

152 @Override153 public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throwsIOException {154 ByteJavaFileObject javaFileObject = newByteJavaFileObject(className, kind);155 javaFileObjectMap.put(className, javaFileObject);156 returnjavaFileObject;157 }158 }159

160 /**

161 * 自定义类加载器, 用来加载动态的字节码162 */

163 private class StringClassLoader extendsClassLoader {164 @Override165 protected Class> findClass(String name) throwsClassNotFoundException {166 ByteJavaFileObject fileObject =javaFileObjectMap.get(name);167 if (fileObject != null) {168 byte[] bytes =fileObject.getCompiledBytes();169 return defineClass(name, bytes, 0, bytes.length);170 }171 try{172 returnClassLoader.getSystemClassLoader().loadClass(name);173 } catch(Exception e) {174 return super.findClass(name);175 }176 }177 }178

179 public static T invokeMethod(Object object, String methodName, Class>[] classes, Object... args)180 throwsException {181 Method method =object.getClass().getMethod(methodName, classes);182 return(T) method.invoke(object, args);183 }184

185 public static voidmain(String[] args) {186 String code = "public class Test {\n" +

187 " public static int runEveryTick() {\n" +

188 "\t\tfor(int i=0; i < 2; i++){\n" +

189 "\t\t\t System.out.println(10);\n" +

190 "\t\t}\n" +

191 "\t\treturn 1;" +

192 " }\n" +

193 "}";194 CustomJavaCompiler compiler = newCustomJavaCompiler(code);195 boolean res =compiler.compiler();196 if(res) {197 System.out.println("compilerSuccess:" +compiler.getCompilerMessage());198 System.out.println("compilerTime:" +compiler.getCompilerTime());199 try{200 Class> clz =compiler.getCompilerClass();201 int ret = invokeMethod(clz.newInstance(), "runEveryTick", null);202 System.out.println("ret:" +ret);203 } catch(Exception e) {204 e.printStackTrace();205 }206 } else{207 System.out.println("compilerFailed:" +compiler.getCompilerMessage());208 }209 }210

211 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值