私はこれを理解しました。私はに実行していた問題は、カスタムスクリプトによって公開された機能は、エンジンのデフォルトの範囲からバインディングに存在していなかったので、invokeFunction
がNoSuchMethodException
を投げるというものであった:
ScriptContext context = new SimpleScriptContext();
context.setBindings(nashorn.createBindings(), ScriptContext.ENGINE_SCOPE);
engine.eval(customScriptSource, context);
((Invocable) engine).invokeFunction(name, args); //<- NoSuchMethodException thrown
だから私がしなければならなかったものを引き出すましたコンテキストの名前から関数を呼び出すと、次のように明示的に呼び出すことができます。
JSObject function = (JSObject) context.getAttribute(name, ScriptContext.ENGINE_SCOPE);
function.call(null, args); //call to JSObject#isFunction omitted brevity
これは、新しく作成されたコンテキストに存在する関数を呼び出します。あなたはまた、オブジェクトのメソッドをこのように呼び出すことができます。
JSObject object = (JSObject) context.getAttribute(name, ScriptContext.ENGINE_SCOPE);
JSObject method = (JSObject) object.getMember(name);
method.call(object, args);
call
はチェックされない例外がスローされます(Throwable
ではJavaScriptスタックフレームの情報で初期化されているRuntimeException
またはNashornException
に包まれたいずれか)ので、あなたがあれば、明示的にことを処理する必要があります有用なフィードバックを提供したい。
スレッドごとに別々のコンテキストが存在するため、この方法ではスレッド間でステップオーバーすることはできません。また、スレッド間でカスタムランタイムコードを共有し、カスタムランタイムによって公開される可変オブジェクトへの状態変更がコンテキストごとに分離されていることを確認できました。これを行うには
、私は私のカスタムランタイム・ライブラリのコンパイル表現を含むCompiledScript
インスタンスを作成します。
public class Runtime {
private ScriptEngine engine;
private CompiledScript compiledRuntime;
public Runtime() {
engine = new NashornScriptEngineFactory().getScriptEngine("-strict");
String source = new Scanner(
this.getClass().getClassLoader().getResourceAsStream("runtime/runtime.js")
).useDelimiter("\\Z").next();
try {
compiledRuntime = ((Compilable) engine).compile(source);
} catch(ScriptException e) {
...
}
}
...
}
は私がスクリプトを実行する必要があるときそれから私は、コンパイルされたソースを評価して、評価しますそのコンテキストに対してスクリプトだけでなく:
ScriptContext context = new SimpleScriptContext();
context.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
//Exception handling omitted for brevity
//Evaluate the compiled runtime in our new context
compiledRuntime.eval(context);
//Evaluate the source in the same context
engine.eval(source, context);
//Call a function
JSObject jsObject = (JSObject) context.getAttribute(function, ScriptContext.ENGINE_SCOPE);
jsObject.call(null, args);
私は複数のスレッドでこれをテストし、私は状態変化が個々のスレッドに属しているコンテキストに限られていたことを確認することができました。これは、コンパイルされた表現が特定のコンテキスト内で実行されるためです。つまり、それによって公開されるすべてのインスタンスがそのコンテキストにスコープされます。
小さな欠点は、スレッド固有の状態を持つ必要のないオブジェクトのオブジェクト定義を不必要に再評価することです。これを回避するには、エンジンのENGINE_SCOPE
にそれらのオブジェクトのバインディングを追加しますこれは、直接エンジンにそれらを評価:
:
public Runtime() {
...
String shared = new Scanner(
this.getClass().getClassLoader().getResourceAsStream("runtime/shared.js")
).useDelimiter("\\Z").next();
try {
...
nashorn.eval(shared);
...
} catch(ScriptException e) {
...
}
}
その後、あなたは、エンジンのENGINE_SCOPE
からスレッド固有のコンテキストを移入することができます
context.getBindings(ScriptContext.ENGINE_SCOPE).putAll(engine.getBindings(ScriptContext.ENGINE_SCOPE));
あなたがする必要があることは、そのようなオブジェクトが公開されていることを確認することです。それ以外の場合は、プロパティを再定義または追加することができます。
プレコンパイルは実際にはNashornのノーオペレーションなので、それは役に立たないと読んでいます。しかし、ソースを見つけることができません。私は間違っている可能性がある。 –