家用电脑系统-新建论坛

java编译器
2023年4月6日发(作者:epson打印机驱动)

java在线编译器的实现_java动态编译(java在线执⾏代码后端

实现原理)(⼆)...

在上⼀篇java动态编译(java在线执⾏代码后端实现原理(⼀))⽂章中实现了字符串编译成字节码,然后通过反射来运⾏代码的demo。这⼀

篇⽂章提供⼀个如何防⽌死循环的代码占⽤cpu的问题。

思路:由于CustomStringJavaCompiler中重定向了的输出位置,肯定不能有多线程并发的情况,否则会照成输

出内容错乱,所以我⽤了edThreadPool(1),通过Future模式来获取结果,我⾃定义了⼀个CustomCallable来处理

核⼼逻辑,在call⽅法中重新new了⼀个Thread来编译并执⾏代码,然后通过join等待N秒之后强制stop掉正在运⾏的线程。这样就能及时

的kill掉动态运⾏的代码。

CustomStringJavaCompiler编译核⼼类

;

stic;

sticCollector;

ject;

dingJavaFileManager;

mpiler;

leManager;

leObject;

JavaFileObject;

rdJavaFileManager;

ovider;

rayOutputStream;

ption;

Stream;

tream;

ortedEncodingException;

tionTargetException;

;

;

;

;

;

rentHashMap;

r;

n;

/**

*Createbyandyon2018-12-0621:25

*/

publicclassCustomStringJavaCompiler{

//类全名

privateStringfullClassName;

privateStringsourceCode;

//存放编译之后的字节码(key:类全名,value:编译之后输出的字节码)

privateMapjavaFileObjectMap=newConcurrentHashMap<>();

//获取java的编译器

privateJavaCompilercompiler=temJavaCompiler();

//存放编译过程中输出的信息

privateDiagnosticCollectordiagnosticsCollector=newDiagnosticCollector<>();

//执⾏结果(控制台输出的内容)

privateStringrunResult;

//编译耗时(单位ms)

privatelongcompilerTakeTime;

//运⾏耗时(单位ms)

privatelongrunTakeTime;

publicCustomStringJavaCompiler(StringsourceCode){

Code=sourceCode;

assName=getFullClassName(sourceCode);

}

/**

*编译字符串源代码,编译失败在diagnosticsCollector中获取提⽰信息

*

*@returntrue:编译成功false:编译失败

*/

publicbooleancompiler(){

longstartTime=tTimeMillis();

//标准的内容管理器,更换成⾃⼰的实现,覆盖部分⽅法

StandardJavaFileManagerstandardFileManager=ndardFileManager(diagnosticsCollector,null,null);

JavaFileManagerjavaFileManager=newStringJavaFileManage(standardFileManager);

//构造源代码对象

JavaFileObjectjavaFileObject=newStringJavaFileObject(fullClassName,sourceCode);

//获取⼀个编译任务

ationTasktask=k(null,javaFileManager,diagnosticsCollector,null,null,

(javaFileObject));

//设置编译耗时

compilerTakeTime=tTimeMillis()-startTime;

();

}

/**

*执⾏main⽅法,重定向

*/

publicvoidrunMainMethod()throwsClassNotFoundException,NoSuchMethodException,InvocationTargetException,

IllegalAccessException,UnsupportedEncodingException{

PrintStreamout=;

try{

longstartTime=tTimeMillis();

ByteArrayOutputStreamoutputStream=newByteArrayOutputStream();

PrintStreamprintStream=newPrintStream(outputStream);

//PrintStreamPrintStream=newPrintStream("/Users/andy/Desktop/");//输出到⽂件

(printStream);//测试kill线程暂时屏蔽

StringClassLoaderscl=newStringClassLoader();

Class>aClass=ass(fullClassName);

Methodmain=hod("main",String[].class);

Object[]pars=newObject[]{1};

pars[0]=newString[]{};

(null,pars);//调⽤main⽅法

//设置运⾏耗时

runTakeTime=tTimeMillis()-startTime;

//设置打印输出的内容

runResult=newString(Array(),"utf-8");

}finally{

//还原默认打印的对象

(out);

}

}

/**

*@return编译信息(错误警告)

*/

publicStringgetCompilerMessage(){

StringBuildersb=newStringBuilder();

List>diagnostics=gnostics();

for(Diagnosticdiagnostic:diagnostics){

(ng()).append("rn");

}

ng();

}

/**

*@return控制台打印的信息

*/

publicStringgetRunResult(){

returnrunResult;

}

publiclonggetCompilerTakeTime(){

returncompilerTakeTime;

}

publiclonggetRunTakeTime(){

returnrunTakeTime;

}

/**

*获取类的全名称

*

*@paramsourceCode源码

*@return类的全名称

*/

publicstaticStringgetFullClassName(StringsourceCode){

StringclassName="";

Patternpattern=e("packages+S+s*;");

Matchermatcher=r(sourceCode);

if(()){

className=().replaceFirst("package","").replace(";","").trim()+".";

}

pattern=e("classs+S+s+{");

matcher=r(sourceCode);

if(()){

className+=().replaceFirst("class","").replace("{","").trim();

}

returnclassName;

}

/**

*⾃定义⼀个字符串的源码对象

*/

privateclassStringJavaFileObjectextendsSimpleJavaFileObject{

//等待编译的源码字段

privateStringcontents;

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

publicStringJavaFileObject(StringclassName,Stringcontents){

super(("string:///"+eAll(".","/")+ion),);

ts=contents;

}

//字符串源码会调⽤该⽅法

@Override

publicCharSequencegetCharContent(booleanignoreEncodingErrors)throwsIOException{

returncontents;

}

}

/**

*⾃定义⼀个编译之后的字节码对象

*/

privateclassByteJavaFileObjectextendsSimpleJavaFileObject{

//存放编译后的字节码

privateByteArrayOutputStreamoutPutStream;

publicByteJavaFileObject(StringclassName,Kindkind){

super(("string:///"+eAll(".","/")+ion),kind);

}

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

@Override

publicOutputStreamopenOutputStream(){

outPutStream=newByteArrayOutputStream();

returnoutPutStream;

}

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

publicbyte[]getCompiledBytes(){

Array();

}

}

/**

*⾃定义⼀个JavaFileManage来控制编译之后字节码的输出位置

*/

privateclassStringJavaFileManageextendsForwardingJavaFileManager{

StringJavaFileManage(JavaFileManagerfileManager){

super(fileManager);

}

//获取输出的⽂件对象,它表⽰给定位置处指定类型的指定类。

@Override

publicJavaFileObjectgetJavaFileForOutput(Locationlocation,StringclassName,nd,FileObjectsibling)

throwsIOException{

ByteJavaFileObjectjavaFileObject=newByteJavaFileObject(className,kind);

(className,javaFileObject);

returnjavaFileObject;

}

}

/**

*⾃定义类加载器,⽤来加载动态的字节码

*/

privateclassStringClassLoaderextendsClassLoader{

@Override

protectedClass>findClass(Stringname)throwsClassNotFoundException{

ByteJavaFileObjectfileObject=(name);

if(fileObject!=null){

byte[]bytes=piledBytes();

returndefineClass(name,bytes,0,);

}

try{

temClassLoader().loadClass(name);

}catch(Exceptione){

ass(name);

}

}

}

}

CustomCallable调⽤编译并运⾏,设置超时时间

;

tionTargetException;

le;

/**

*Createbyandyon2018-12-0713:10

*/

publicclassCustomCallableimplementsCallable{

privateStringsourceCode;

publicCustomCallable(StringsourceCode){

Code=sourceCode;

}

//⽅案1

//@Override

//publicRunInfocall()throwsException{

//n("开始执⾏call"+());

//RunInforunInfo=newRunInfo();

//CustomStringJavaCompilercompiler=newCustomStringJavaCompiler(sourceCode);

//if(er()){

//pilerSuccess(true);

//try{

//nMethod();

//Success(true);

//TakeTime(TakeTime());

//Message(Result());//获取运⾏的时候输出内容

//}catch(Exceptione){

//tackTrace();

//Success(false);

//Message(sage());

//}

//}else{

////编译失败

//pilerSuccess(false);

//}

//pilerTakeTime(pilerTakeTime());

//pilerMessage(pilerMessage());

//n("callover"+());

//returnrunInfo;

//}

//⽅案2

@Override

publicRunInfocall()throwsException{

RunInforunInfo=newRunInfo();

Threadt1=newThread(()->realCall(runInfo));

();

try{

(3000);//等待3秒

}catch(InterruptedExceptione){

tackTrace();

}

//不管有没有正常执⾏完成,强制停⽌t1

();

returnrunInfo;

}

privatevoidrealCall(RunInforunInfo){

CustomStringJavaCompilercompiler=newCustomStringJavaCompiler(sourceCode);

if(er()){

pilerSuccess(true);

try{

nMethod();

Success(true);

TakeTime(TakeTime());

Message(Result());//获取运⾏的时候输出内容

}catch(InvocationTargetExceptione){

//反射调⽤异常了,是因为超时的线程被强制stop了

if("Death".equalsIgnoreCase(se().toString())){

return;

}

}catch(Exceptione){

tackTrace();

Success(false);

Message(sage());

}

}else{

//编译失败

pilerSuccess(false);

}

pilerTakeTime(pilerTakeTime());

pilerMessage(pilerMessage());

eOut(false);//⾛到这⼀步代表没有超时

}

}

RunInfo动态编译、运⾏信息的bean

publicclassRunInfo{

//true:代表超时

privateBooleantimeOut;

privateLongcompilerTakeTime;

privateStringcompilerMessage;

privateBooleancompilerSuccess;

privateLongrunTakeTime;

privateStringrunMessage;

privateBooleanrunSuccess;

//省略get和set⽅法

}

CompilerUtil把⼀整套流程封装了⼀个⼯具类

;

orService;

ors;

;

/**

*Createbyandyon2018-12-0716:32

*/

publicclassCompilerUtil{

//这⾥⽤⼀个线程是因为防⽌输出内容错乱

privatestaticExecutorServicepool=edThreadPool(1);

publicstaticRunInfogetRunInfo(StringjavaSourceCode){

RunInforunInfo;

CustomCallablecompilerAndRun=newCustomCallable(javaSourceCode);

Futurefuture=(compilerAndRun);

//⽅案1

try{

runInfo=();

}catch(Exceptione){

tackTrace();

//代码编译或者运⾏超时

runInfo=newRunInfo();

eOut(true);

}

//⽅案2:不可⾏的原因:超时会有问题,由于线程池只有1个线程,同时提交10个任务,当前⾯⼏个任务执⾏时间很长,后⾯

调⽤get就会⽴马失败,也就是说get的超时时间是从调⽤get开始算的,并不是线程真正执⾏时间开始计算的

//try{

//runInfo=(5,S);

//returnrunInfo;

//}catch(InterruptedExceptione){

//n("future在睡着时被打断");

//tackTrace();

//}catch(ExecutionExceptione){

//n("future在尝试取得任务结果时出错");

//tackTrace();

//}catch(TimeoutExceptione){

//n("future时间超时");

//tackTrace();

//(true);

//}

//runInfo=newRunInfo();

//eOut(true);

returnrunInfo;

}

}

测试类:

;

/**

*Createbyandyon2018-12-1010:43

*/

publicclassTest3{

publicstaticvoidmain(String[]args)throwsInterruptedException{

Stringloop="publicclassHelloWorld{n"+

"publicstaticvoidmain(String[]args){n"+

"while(true){n"+

//"n("HelloWorld!");n"+

"}n"+

"n"+

"}n"+

"}";

Stringsleep_loop="publicclassHelloWorld{n"+

"publicstaticvoidmain(String[]args){n"+

"try{n"+

"(6000);n"+

"}catch(InterruptedExceptione){n"+

"tackTrace();n"+

"}n"+

"n("HelloWorld!");n"+

"while(true){n"+

//"n("HelloWorld!");n"+

"}n"+

"}n"+

"}";

Stringok="publicclassHelloWorld{n"+

"publicstaticvoidmain(String[]args){n"+

"n("HelloWorld!");n"+

"}n"+

"}";

TestRunt=newTestRun(ok,"thread:ok");

();

TestRunt1=newTestRun(loop,"thread:loop:");

();

//

TestRunt2=newTestRun(sleep_loop,"thread:sleep_loop:");

();

}

}

classTestRunextendsThread{

Stringcode;

TestRun(Stringcode,Stringname){

=code;

e(name);

}

@Override

publicvoidrun(){

n(Info(code));

}

}

更多推荐

java编译器