7

Rhino 引擎是否有 api 可以在中间停止执行脚本文件。例如,我有一个脚本文件,其中有一个无限循环。我怎样才能在中间停止执行?

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

4

4 回答 4

7

可以使用以下方式停止正在运行的 JavaScript 的执行。

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

mContext = Context.enter();
ObservingDebugger observingDebugger = new ObservingDebugger();
mContext.setDebugger(observingDebugger, new Integer(0));
mContext.setGeneratingDebug(true);
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 Execution 将立即终止。

observingDebugger.setDisconnected(true);
于 2012-04-26T10:48:33.643 回答
4

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

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

于 2013-04-23T21:22:52.277 回答
1

我使用 ExecutorService 和超时的 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();
    }
于 2015-11-13T17:24:20.723 回答
-2

Rhino 引擎似乎没有任何机制来执行此操作(坏 Rhino!)并且很难判断它是否在内部创建线程,因此您唯一的解决方案是创建一个ThreadGroup,加载并执行 Rhino 引擎和它的脚本来自该组中的一个线程,当你想杀死它时,使用ThreadGroup.stop(). 是的,它已被弃用,但考虑到 Rhino 图书馆方面没有合作,确实没有其他方法可以做到这一点。

于 2012-04-20T12:33:49.537 回答