Nashorn移除后,JS脚本改由GraalVM.js在独立运行时执行,通过Polyglot桥接Java;变量需显式注入、全局对象隔离、类型映射更严谨、作用域不跨上下文复用。

Nashorn被彻底移除后,变量脚本处理方式发生了本质变化:不再是“JS代码直接跑在JVM字节码上”,而是“JS在独立语言运行时中执行,再通过Polyglot桥接Java上下文”。这种更迭不是简单替换引擎,而是重构了脚本生命周期、变量作用域模型和类型交互逻辑。
变量绑定机制从隐式到显式
Nashorn默认将Java对象自动挂载到全局作用域(如Packages、Java、global),脚本里可直接写Java.type("java.util.ArrayList")或Packages.java.lang.System.currentTimeMillis()。这种隐式暴露带来便利,也埋下安全与维护隐患。
GraalVM.js默认关闭所有主机访问,变量必须显式注入:
- 用
context.getBindings("js").putMember("utils", new JsUtils())手动绑定Java对象 - 用
context.eval("js", "console.log(utils.now())")才能调用 - 不绑定的Java类、系统属性、线程上下文一律不可见
全局对象语义发生偏移
Nashorn中this、global、globalThis三者行为趋同,且与ScriptEngine的Bindings共享同一作用域。GraalVM.js则严格遵循ECMAScript标准:globalThis是纯粹的JS全局对象,与Java Host对象物理隔离。
常见断裂点包括:
-
global.myConfig = { timeout: 5000 }在Nashorn中生效,GraalVM中该赋值仅存在于JS沙箱内,Java侧无法读取 -
Java.type在GraalVM中默认不存在,需启用--js.nashorn-compat=true并配合--experimental-options -
load("config.js")这类Nashorn特有函数已被移除,须改用context.eval("js", Files.readString(...))
变量类型映射更严谨但需适配
Nashorn对Java→JS类型转换较宽松:List自动转JS数组,Map自动转JS对象,null/undefined常被混用。GraalVM.js保持类型精确性,映射规则由Polyglot协议定义:
- Java
Integer→ JSnumber(无精度损失) - Java
LocalDateTime→ JSValue对象(非原生Date,需.as(Date.class)显式转换) - Java
ArrayList<string></string>→ JSValue(可用.getArraySize()和.getArrayElement(i)遍历,但.length不可用) - JS原始值传入Java方法时,若目标参数为
Object,GraalVM保留其Value封装;若为具体类型(如String),会尝试asString().toString()转换
脚本级变量复用需主动管理
Nashorn中多次engine.eval(script)可复用同一ScriptContext中的变量状态;GraalVM中每次Context.create()都是全新隔离环境,变量不跨上下文存活。
高频场景建议:
- 用
Context.newBuilder().allowHostAccess(...).build()创建长期复用的Context实例(注意线程安全) - 将配置类、工具类等作为
Value预绑定到Bindings,避免重复eval初始化 - 对纯计算脚本,启用
.option("engine.CompileOnly", "true")提升重复执行性能











