spe*_*0ne 6 java api scripting
我写了一个servlet,它收集了一个java脚本代码并处理它并返回答案.因为我使用了java脚本API
在下面的代码中,如果script ="print('Hello,World')"; 代码将正确打印"hello world".但如果script ="while(true);" 脚本将无休止地循环.
import javax.script.*;
public class EvalScript {
public static void main(String[] args) throws Exception {
// create a script engine manager
ScriptEngineManager factory = new ScriptEngineManager();
// create a JavaScript engine
ScriptEngine engine = factory.getEngineByName("JavaScript");
// evaluate JavaScript code from String
engine.eval(script);
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,如果需要太长时间(比如15秒),我如何杀死eval过程?
谢谢
这是一些显示 Future 实现和 Thread.stop() 的代码。这是一个有趣的问题,它指出在 ScriptEngine 中需要一个钩子,以便能够停止无论出于何种原因正在运行的任何脚本。我想知道这是否会打破大多数实现中的假设,因为它们假设eval()将在单线程(阻塞)环境中执行?
无论如何,执行以下代码的结果:
// exec with Thread.stop()
$ java ExecJavascript
Java: Starting thread...
JS: Before infinite loop...
Java: ...thread started
Java: Thread alive after timeout, stopping...
Java: ...thread stopped
(program exits)
// exec with Future.cancel()
$ java ExecJavascript 1
Java: Submitting script eval to thread pool...
Java: ...submitted.
JS: Before infinite loop...
Java: Timeout! trying to future.cancel()...
Java: ...future.cancel() executed
(program hangs)
Run Code Online (Sandbox Code Playgroud)
这是完整的程序:
import java.util.concurrent.*;
import javax.script.*;
public class ExecJavascript
{
private static final int TIMEOUT_SEC = 5;
public static void main( final String ... args ) throws Exception
{
final ScriptEngine engine = new ScriptEngineManager()
.getEngineByName("JavaScript");
final String script =
"var out = java.lang.System.out;\n" +
"out.println( 'JS: Before infinite loop...' );\n" +
"while( true ) {}\n" +
"out.println( 'JS: After infinite loop...' );\n";
if ( args.length == 0 ) {
execWithThread( engine, script );
}
else {
execWithFuture( engine, script );
}
}
private static void execWithThread(
final ScriptEngine engine, final String script )
{
final Runnable r = new Runnable() {
public void run() {
try {
engine.eval( script );
}
catch ( ScriptException e ) {
System.out.println(
"Java: Caught exception from eval(): " + e.getMessage() );
}
}
};
System.out.println( "Java: Starting thread..." );
final Thread t = new Thread( r );
t.start();
System.out.println( "Java: ...thread started" );
try {
Thread.currentThread().sleep( TIMEOUT_SEC * 1000 );
if ( t.isAlive() ) {
System.out.println( "Java: Thread alive after timeout, stopping..." );
t.stop();
System.out.println( "Java: ...thread stopped" );
}
else {
System.out.println( "Java: Thread not alive after timeout." );
}
}
catch ( InterruptedException e ) {
System.out.println( "Interrupted while waiting for timeout to elapse." );
}
}
private static void execWithFuture( final ScriptEngine engine, final String script )
throws Exception
{
final Callable<Object> c = new Callable<Object>() {
public Object call() throws Exception {
return engine.eval( script );
}
};
System.out.println( "Java: Submitting script eval to thread pool..." );
final Future<Object> f = Executors.newCachedThreadPool().submit( c );
System.out.println( "Java: ...submitted." );
try {
final Object result = f.get( TIMEOUT_SEC, TimeUnit.SECONDS );
}
catch ( InterruptedException e ) {
System.out.println( "Java: Interrupted while waiting for script..." );
}
catch ( ExecutionException e ) {
System.out.println( "Java: Script threw exception: " + e.getMessage() );
}
catch ( TimeoutException e ) {
System.out.println( "Java: Timeout! trying to future.cancel()..." );
f.cancel( true );
System.out.println( "Java: ...future.cancel() executed" );
}
}
}
Run Code Online (Sandbox Code Playgroud)
在单独的线程中运行评估,并在 15 秒后使用 Thread.interrupt() 中断它。这将停止 eval 并抛出 InterruptedException,您可以捕获该异常并返回失败状态。
更好的解决方案是为脚本引擎提供某种异步接口,但据我所知,这并不存在。
编辑:
正如 sfussenegger 指出的那样,中断不适用于脚本引擎,因为它永远不会休眠或进入任何等待状态来中断。我无法在 ScriptContext 或 Bindings 对象中找到任何可用作检查中断的钩子的定期回调。不过,有一种方法确实有效:Thread.stop()。由于多种原因,它已被弃用并且本质上不安全,但为了完整性,我将在此处发布我的测试代码以及 Chris Winters 实现以进行比较。Chris 的版本会超时,但让后台线程继续运行,interrupt() 不执行任何操作,stop() 会终止线程并恢复对主线程的控制:
import javax.script.*;
import java.util.concurrent.*;
class ScriptRunner implements Runnable {
private String script;
public ScriptRunner(String script) {
this.script = script;
}
public ScriptRunner() {
this("while(true);");
}
public void run() {
try {
// create a script engine manager
ScriptEngineManager factory = new ScriptEngineManager();
// create a JavaScript engine
ScriptEngine engine = factory.getEngineByName("JavaScript");
// evaluate JavaScript code from String
System.out.println("running script :'" + script + "'");
engine.eval(script);
System.out.println("stopped running script");
} catch(ScriptException se) {
System.out.println("caught exception");
throw new RuntimeException(se);
}
System.out.println("exiting run");
}
}
public class Inter {
public void run() {
try {
Executors.newCachedThreadPool().submit(new ScriptRunner()).get(15, TimeUnit.SECONDS);
} catch(Exception e) {
throw new RuntimeException(e);
}
}
public void run2() {
try {
Thread t = new Thread(new ScriptRunner());
t.start();
Thread.sleep(1000);
System.out.println("interrupting");
t.interrupt();
Thread.sleep(5000);
System.out.println("stopping");
t.stop();
} catch(InterruptedException ie) {
throw new RuntimeException(ie);
}
}
public static void main(String[] args) {
new Inter().run();
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8824 次 |
| 最近记录: |