java在线编译器的实现_java动态编译(java在线执⾏代码后端
实现原理)(⼆)...
在上⼀篇java动态编译 (java在线执⾏代码后端实现原理(⼀))⽂章中实现了 字符串编译成字节码,然后通过反射来运⾏代码的demo。这⼀篇⽂章提供⼀个如何防⽌死循环的代码占⽤cpu的问题。
思路:由于CustomStringJavaCompiler中重定向了System.out的输出位置,肯定不能有多线程并发的情况,否则会照成System.out输出内容错乱,所以我⽤了 wFixedThreadPool(1), 通过Future模式来获取结果,我⾃定义了⼀个CustomCallable来处理核⼼逻辑,在call⽅法中重新new 了⼀个Thread来编译并执⾏代码,然后通过join等待N秒之后强制stop掉正在运⾏的线程。这样就能及时的kill掉动态运⾏的代码。
CustomStringJavaCompiler 编译核⼼类
demo;
ls.Diagnostic;
ls.DiagnosticCollector;
ls.FileObject;
ls.ForwardingJavaFileManager;
ls.JavaCompiler;
ls.JavaFileManager;
ls.JavaFileObject;
ls.SimpleJavaFileObject;
ls.StandardJavaFileManager;
ls.ToolProvider;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import flect.InvocationTargetException;
import flect.Method;
import java.URI;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import urrent.ConcurrentHashMap;
import Matcher;
import Pattern;
/
**
* Create by andy on 2018-12-06 21:25
*/
public class CustomStringJavaCompiler {
//类全名
private String fullClassName;
private String sourceCode;
//存放编译之后的字节码(key:类全名,value:编译之后输出的字节码)
private Map javaFileObjectMap = new ConcurrentHashMap<>();
//获取java的编译器
private JavaCompiler compiler = SystemJavaCompiler();
/
/存放编译过程中输出的信息
private DiagnosticCollector diagnosticsCollector = new DiagnosticCollector<>();
//执⾏结果(控制台输出的内容)
private String runResult;
//编译耗时(单位ms)
private long compilerTakeTime;
//运⾏耗时(单位ms)
private long runTakeTime;
public CustomStringJavaCompiler(String sourceCode) {
this.sourceCode = sourceCode;
this.fullClassName = getFullClassName(sourceCode);
}
/**
* 编译字符串源代码,编译失败在 diagnosticsCollector 中获取提⽰信息
*
* @return true:编译成功 false:编译失败
*/
public boolean compiler() {
long startTime = System.currentTimeMillis();
//标准的内容管理器,更换成⾃⼰的实现,覆盖部分⽅法
StandardJavaFileManager standardFileManager = StandardFileManager(diagnosticsCollector, null, null); JavaFileManager javaFileManager = new StringJavaFileManage(standardFileManager);
//构造源代码对象
JavaFileObject javaFileObject = new StringJavaFileObject(fullClassName, sourceCode);
//获取⼀个编译任务
JavaCompiler.CompilationTask task = Task(null, javaFileManager, diagnosticsCollector, null, null, Arrays.asList(javaFileObject));
//设置编译耗时
compilerTakeTime = System.currentTimeMillis() - startTime;
return task.call();
}
/**
* 执⾏main⽅法,重定向System.out.print
*/
public void runMainMethod() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, UnsupportedEncodingException {
PrintStream out = System.out;
try {
long startTime = System.currentTimeMillis();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PrintStream printStream = new PrintStream(outputStream);
//PrintStream PrintStream = new PrintStream("/Users/andy/Desktop/tem.sql"); //输出到⽂件
System.setOut(printStream); //测试kill线程暂时屏蔽
StringClassLoader scl = new StringClassLoader();
Class> aClass = scl.findClass(fullClassName);
Method main = Method("main", String[].class);
Object[] pars = new Object[]{1};
pars[0] = new String[]{};
main.invoke(null, pars); //调⽤main⽅法
//设置运⾏耗时
runTakeTime = System.currentTimeMillis() - startTime;
//设置打印输出的内容
runResult = new ByteArray(), "utf-8");
} finally {
//还原默认打印的对象
System.setOut(out);
}
}
/**
* @return 编译信息(错误 警告)
*/
public String getCompilerMessage() {
StringBuilder sb = new StringBuilder();
List> diagnostics = Diagnostics();
for (Diagnostic diagnostic : diagnostics) {
sb.String()).append("\r\n");
}
String();
}
/**
* @return 控制台打印的信息
*/
public String getRunResult() {
return runResult;
}
public long getCompilerTakeTime() {
return compilerTakeTime;
}
public long getRunTakeTime() {
return runTakeTime;
}
/**
* 获取类的全名称
*
* @param sourceCode 源码
* @return 类的全名称
*/
public static String getFullClassName(String sourceCode) {
String className = "";
Pattern pattern = Patternpile("package\\s+\\S+\\s*;");
Matcher matcher = pattern.matcher(sourceCode);
if (matcher.find()) {
className = up().replaceFirst("package", "").replace(";", "").trim() + ".";
}
pattern = Patternpile("class\\s+\\S+\\s+\\{");
matcher = pattern.matcher(sourceCode);
if (matcher.find()) {
className += up().replaceFirst("class", "").replace("{", "").trim();
}
return className;
}
/
**
* ⾃定义⼀个字符串的源码对象
*/
private class StringJavaFileObject extends SimpleJavaFileObject {
//等待编译的源码字段
private String contents;
//java源代码 => StringJavaFileObject对象 的时候使⽤
public StringJavaFileObject(String className, String contents) {
ate("string:///" + placeAll("\\.", "/") + sion), Kind.SOURCE); ts = contents;
}
//字符串源码会调⽤该⽅法
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {java源代码加密
return contents;
}
}
/**
* ⾃定义⼀个编译之后的字节码对象
*/
private class ByteJavaFileObject extends SimpleJavaFileObject {
//存放编译后的字节码
private ByteArrayOutputStream outPutStream;
public ByteJavaFileObject(String className, Kind kind) {
ate("string:///" + placeAll("\\.", "/") + sion), kind);
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论