犀牛引擎是否有一個可以停止執行中間腳本的API。例如,我有一個腳本文件,其中 有一個無限循環。我怎樣才能在中間停止執行?停止犀牛引擎執行中
當然,我可以阻止啓動Rhino引擎的jvm改爲 。但我不想因爲這個原因殺死整個jvm會話,因爲我已經以編程方式啓動腳本,並且Rhino引擎也與我的應用程序在相同的JVM中運行。
犀牛引擎是否有一個可以停止執行中間腳本的API。例如,我有一個腳本文件,其中 有一個無限循環。我怎樣才能在中間停止執行?停止犀牛引擎執行中
當然,我可以阻止啓動Rhino引擎的jvm改爲 。但我不想因爲這個原因殺死整個jvm會話,因爲我已經以編程方式啓動腳本,並且Rhino引擎也與我的應用程序在相同的JVM中運行。
停止運行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執行將立即終止。
observingDebugger.setDisconnected(true);
犀牛引擎doesn't appear有這樣做的機制(壞的犀牛!),很難說它是否在內部創建線程,所以唯一的解決辦法是創建一個ThreadGroup
,加載並執行Rhino引擎及其腳本從該組中的線程中移除,並且當您想要將其關閉時,請使用ThreadGroup.stop()
。是的,它已被棄用,但由於Rhino庫沒有合作,所以沒有其他辦法可以做到。
爲別人尋找一個解決方案,爲ContextFactory的Javadoc詳細介紹瞭如何阻止腳本運行時間超過10秒:
https://github.com/mozilla/rhino/blob/master/src/org/mozilla/javascript/ContextFactory.java
自定義的ContextFactory方法出色地工作。如果您在閱讀Java中的javadoc時遇到問題,請在這裏閱讀HTML版本:http://www.jarvana.com/jarvana/view/org/mozilla/rhino/1.7R3/rhino-1.7R3-javadoc.jar!/org /mozilla/javascript/ContextFactory.html – kevinjansz 2013-05-02 00:10:20
我想知道這個和調試器方法的性能影響。有任何想法嗎? – HRJ 2015-09-16 08:20:16
我會想象調試器方法會對性能產生一些影響,因爲上下文正在生成調試信息。 ContextFactory解決方案只是在執行了一定數量的指令之後觸發。 – bigspotteddog 2015-09-16 18:18:32
我使用的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;
}
}
創建任何背景對象之前,你需要配置你的應用程序使用此ContextFactory爲默認值,只需調用
InterruptableContextFactory.init()
內,您的可贖回的呼叫的方法,你可以捕捉到錯誤:
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();
}
@多納爾:這可能PR obably不起作用,因爲一旦我創建新線程並開始加載並執行Rhino引擎,一旦上下文的evaluateReader()方法被調用,線程執行完成並且Rhino引擎在內部管理執行。 – Syam 2012-04-26 10:21:18
這就是爲什麼我建議把它放在自己的線程組中;由Rhino創建的任何其他線程仍將位於該線程組(或一個子線程組)中,因此仍然有可能將它們全部__全部拋出。 – 2012-04-26 12:27:56