为什么您的代码不起作用
全局作用域只能用于简单的变量映射。例如:
ScriptContext defCtx = engine.getContext();
defCtx.getBindings(ScriptContext.GLOBAL_SCOPE).put("foo","hello");
Object
位于引擎范围内,因此甚至不会在全局范围内搜索与其相关的任何映射(在您的情况下为Object.prototype.test
)。
文档摘录:
默认上下文的ENGINE_SCOPE是ECMAScript“全局”对象的包装实例-顶级脚本表达式中的“ this”。因此,您可以从此范围对象访问ECMAScript顶级对象,例如“对象”,“数学”,“ RegExp”,“未定义”。 Nashorn全局范围对象由称为jdk.nashorn.internal.objects.Global的内部实现类表示。此类的实例包装为jdk.nashorn.api.scripting.ScriptObjectMirror实例。 ScriptObjectMirror类实现javax.script.Bindings接口。 请注意,上下文的GLOBAL_SCOPE绑定和nashorn全局对象是不同的。 Nashorn的全局对象与ENGINE_SCOPE关联,而不与GLOBAL_SCOPE关联。默认脚本上下文的GLOBAL_SCOPE对象是javax.script.SimpleBindings实例。用户可以使用Java代码中的名称和值对来填充它。
https://wiki.openjdk.java.net/display/Nashorn/Nashorn+jsr223+engine+notes
解决方案
- 继续使用引擎范围
- 通过在Java命令行中指定
--global-per-engine option
来使用-Dnashorn.args=--global-per-engine
。然后,Nashorn将使用全局对象的单个实例进行所有脚本评估,而与传递的ScriptContext无关。
- 使用成熟的ScriptContext代替绑定:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
SimpleScriptContext context = new SimpleScriptContext();
engine.eval("Object.prototype.test = function(arg){print(arg);}",context);
engine.eval("var x = {}; x.test('hello');",context);
如何在每次加载库时运行多个脚本,但以前的执行没有任何作用
每次需要使用库的新上下文时,只需创建它即可:
public static void main(String[] args) throws ScriptException {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
SimpleScriptContext context1 = createContextWithLibraries(engine);
//works as expected,printing "hello"
engine.eval("var x = {}; x.test('hello'); var y = 'world';",context1);
SimpleScriptContext context2 = createContextWithLibraries(engine);
//works as expected,printing "hello"
engine.eval("var x = {}; x.test('hello');",context2);
//works as expected,printing "world"
engine.eval("print(y);",context1);
//fails with exception since there is no "y" variable in context2
engine.eval("print(y);",context2);
}
private static SimpleScriptContext createContextWithLibraries(ScriptEngine engine) throws ScriptException {
SimpleScriptContext context = new SimpleScriptContext();
engine.eval("Object.prototype.test = function(arg){print(arg);}",context);
return context;
}
,
Denis已经解释了这个问题,所以我不再重复他说的话。但是,我将给出另一种解决方案。为了避免一遍又一遍地解析相同的库的开销,可以对其进行编译。这是一种实现方法:
import java.util.*;
import javax.script.*;
public class Test
{
public static List<CompiledScript> compileScripts(ScriptEngine engine,String... scripts) throws ScriptException
{
Compilable compilable = (Compilable)engine;
ArrayList<CompiledScript> list = new ArrayList<>();
for(String script : scripts)
list.add(compilable.compile(script));
return list;
}
public static void execute(ScriptEngine engine,List<CompiledScript> libs,String script) throws ScriptException
{
engine.setBindings(engine.createBindings(),ScriptContext.ENGINE_SCOPE);
for(CompiledScript lib : libs)
lib.eval();
engine.eval(script);
}
public static void main(String[] args) throws ScriptException
{
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");
List<CompiledScript> libs = compileScripts(engine,"var x = 1","Object.prototype.test = function(arg){print(arg)}");
// Prints 'hello'
execute(engine,libs,"x.test('hello')");
// Defines y
execute(engine,"var y = 2");
// Checks that executions have a clean (non-polluted) context
// Throws ReferenceError: "y" is not defined in <eval> at line number 1
execute(engine,"print(y)");
}
}
本文链接:https://www.f2er.com/2545300.html