在执行过程中停止Rhino引擎

Rhino引擎是否有api可以在中间停止执行脚本。 例如,我有一个脚本文件,其中有一个infinte循环。 如何在中间停止执行?

当然,我可以阻止启动Rhino引擎的jvm来执行脚本。 但是我不想因为这个原因而杀死整个jvm会话,因为我已经以编程方式启动了脚本,并且Rhino Engine也在与我的应用程序相同的JVM中运行。

停止执行运行JavaScript可以通过以下方式完成。

1)创建一个虚拟调试器并将其附加到最初创建的上下文。

mContext = Context.enter();
ObservingDebugger observingDebugger = new ObservingDebugger();
mContext.setDebugger(observingDebugger,new Integer(0));
mContext.setGeneratingDebug(真);
mContext.setOptimizationLevel(-1);

ObservingDebugger代码如下所示。

import org.mozilla.javascript.Context; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.debug.DebugFrame; import org.mozilla.javascript.debug.DebuggableScript; import org.mozilla.javascript.debug.Debugger; public class ObservingDebugger implements Debugger { boolean isDisconnected = false; private DebugFrame debugFrame = null; public boolean isDisconnected() { return isDisconnected; } public void setDisconnected(boolean isDisconnected) { this.isDisconnected = isDisconnected; if(debugFrame != null){ ((ObservingDebugFrame)debugFrame).setDisconnected(isDisconnected); } } public ObservingDebugger() { } public DebugFrame getFrame(Context cx, DebuggableScript fnOrScript) { if(debugFrame == null){ debugFrame = new ObservingDebugFrame(isDisconnected); } return debugFrame; } @Override public void handleCompilationDone(Context arg0, DebuggableScript arg1, String arg2) { } } // internal ObservingDebugFrame class class ObservingDebugFrame implements DebugFrame { boolean isDisconnected = false; public boolean isDisconnected() { return isDisconnected; } public void setDisconnected(boolean isDisconnected) { this.isDisconnected = isDisconnected; } ObservingDebugFrame(boolean isDisconnected) { this.isDisconnected = isDisconnected; } public void onEnter(Context cx, Scriptable activation, Scriptable thisObj, Object[] args) { } public void onLineChange(Context cx, int lineNumber) { if(isDisconnected){ throw new RuntimeException("Script Execution terminaed"); } } public void onExceptionThrown(Context cx, Throwable ex) { } public void onExit(Context cx, boolean byThrow, Object resultOrException) { } @Override public void onDebuggerStatement(Context arg0) { } } 

ObservingDebugger类将管理布尔变量“isDisconnected”,当用户单击停止按钮(想要停止执行)时,此变量将设置为true。 一旦变量设置为true,Rhino执行将立即终止。

 observingDebugger.setDisconnected(true); 

对于其他寻找解决方案的人来说,ContextFactory的javadoc详细说明了如何停止运行超过10秒的脚本:

https://github.com/mozilla/rhino/blob/master/src/org/mozilla/javascript/ContextFactory.java

我使用ExecutorService和timed-out future.get在新线程中执行脚本

  ExecutorService executor = Executors.newSingleThreadExecutor(); Future future = executor.submit(threadEvaluation); try { System.out.println("Started.."); future.get(100, TimeUnit.MILLISECONDS); System.out.println("Finished!"); } catch (TimeoutException e) { future.cancel(true); System.out.println("Terminated!"); } 

请注意,此方法不会停止执行脚本的线程! 为此,当执行脚本的线程被通知中断时,您可以创建一个定制监视此情况的自定义ContextFactory:

 public class InterruptableContextFactory extends ContextFactory { public static boolean initialized = false; public static void init() { if (!initialized) { ContextFactory.initGlobal(new InterruptableContextFactory()); initialized = true; } } @Override protected void observeInstructionCount(Context cx, int instructionCount) { System.out.println(instructionCount + " javascript instructions!"); if (Thread.currentThread().isInterrupted()) { throw new Error("script execution aborted"); } } @Override protected Context makeContext() { Context cx = super.makeContext(); //set a number of instructions here cx.setInstructionObserverThreshold(10000); return cx; } } 

在创建任何Context对象之前,您需要将应用程序配置为使用此ContextFactory作为默认值,只需调用即可

 InterruptableContextFactory.init() 

在Callable的调用方法中,您可以捕获错误:

  try { cx.setOptimizationLevel(9); cx.setInstructionObserverThreshold(10000); ScriptableObject scope = cx.initStandardObjects(); // your code here } catch (Error e) { System.out.println("execution was aborted: " + e.getMessage()); } finally { Context.exit(); } 

Rhino引擎似乎没有任何机制来执行此操作(糟糕的Rhino!)并且很难判断它是否在内部创建线程,因此您获得的唯一解决方案是创建ThreadGroup ,加载并执行Rhino引擎它的脚本来自该组中的一个线程,当你想要将其ThreadGroup.stop()时,使用ThreadGroup.stop() 。 是的,它被弃用了但是由于Rhino库没有合作,所以没有别的方法可以做到。