【问题标题】:Setting InstructionObserverThreshold on javax.scripting context在 java.scripting 上下文上设置指令观察者阈值
【发布时间】:2014-01-27 22:18:34
【问题描述】:

我一直在努力解决使用 java 脚本 API 来控制某些用户定义的 javascript 的执行的问题。我在引擎盖下使用内置的 Rhino 引擎,它说您可以设置 InstructionObserverThreshold ,如果达到限制,它将负责停止执行。我一直在玩下面的示例应用程序一段时间,我很困惑为什么它不起作用。你会看到我也设置了MaximumInterpreterStackDepth。这完美地工作,但指令观察者似乎没有做任何事情。

关于此代码缺少什么以使其正常工作的任何想法?

谢谢!

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import com.sun.script.javascript.RhinoScriptEngine;


public class RhinoTester2 {

    public static void main(String[] args) {

    new RhinoScriptEngine(); // initialize the global context.

     sun.org.mozilla.javascript.internal.ContextFactory cx =  sun.org.mozilla.javascript.internal.ContextFactory.getGlobal();
     cx.addListener( new sun.org.mozilla.javascript.internal.ContextFactory.Listener() {
         public void contextCreated( sun.org.mozilla.javascript.internal.Context cxt ) {
                cxt.setInstructionObserverThreshold(10000 ); // This should stop after 10 seconds or so.
                cxt.setMaximumInterpreterStackDepth(1);  // this should not be a factor for the moment
                System.out.println("Context Factory threshold set. "+cxt.getInstructionObserverThreshold());
          }

        @Override
        public void contextReleased(
            sun.org.mozilla.javascript.internal.Context arg0) {
            System.out.println("Context Released.");
        }

     });

       // Now run the script to see if it will be stopped after a short time.
        ScriptEngineManager mgr = new ScriptEngineManager();
        ScriptEngine engine = mgr.getEngineByName("javascript"); 
        try {
            // engine.eval("while(true){println(\"hello\");};"); // This will fail immediately due to the interpreter stack depth.
            engine.eval("while(true){};");  // this never fails.  runs happily forever.
        } catch (ScriptException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

【问题讨论】:

  • 不幸的是,脚本 api 使用的基本 ContextFactory 中似乎没有提供处理 InstructionObservationCount 的推荐方法。在查看 RhinoScriptEngine 时,用户无法修改 ContextFactory 以添加实现(密封类和匿名静态块调用 initGlobal)。据我所知,只有两个选项 - 创建自己的脚本引擎并替换内置版本,或者在线程中管理它并在超过超时时终止线程。令人失望.....

标签: java javascript rhino javax.script


【解决方案1】:

您可以使用自己覆盖的 ContextFactory 版本来执行上下文操作。在方法 makeContext() 中,您可以从头开始创建上下文并设置您想要的指令计数以及其他设置。

我的实现示例:

public class MyContextFactory extends ContextFactory {
    protected Context makeContext() {
        Context cx = new MyContext(this);
        cx.setOptimizationLevel(0);
        cx.setLanguageVersion(Context.VERSION_1_8);
        cx.setInstructionObserverThreshold(100000);
    return cx;
    }
}

如您所见,我还创建了自己的 Context 子类,因为将工厂作为参数的 Context 构造函数受到保护:

public class RhinoContext extends Context {

    public RhinoContext(ContextFactory factory) {
        super(factory);
    }

}

然后您应该能够在调用任何脚本之前通过方法 ContextFactory.initGlobal(factory) 注入您自己的上下文工厂的实例。

但是请注意,我的测试中的指令观察器仅在优化级别

【讨论】:

  • 我曾经试过这个。问题是您不能自己调用​​ ContextFactory.initGlobal。它将破坏试图调用 ContextFactory.initGlobal 的 RhinoScriptEngine 类。它只能被调用一次,之后的任何尝试都会抛出异常。
  • 好的,我不使用 RhinoScriptEngine,这可能就是为什么这对我有用。我仍在使用直接描述here的Context对象的“旧”方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多