Java 11下独立版Nashorn调用eval抛出StackOverflowError问题
Nashorn长表达式eval在Java11环境栈溢出问题修复
问题背景
- 异常现象:对较长逻辑表达式执行
eval求值时,Java 8环境运行正常,Java 11环境抛出java.lang.StackOverflowError,错误堆栈定位到org.openjdk.nashorn.internal.codegen.LocalVariableTypesCalculator的二元节点处理逻辑 - 已尝试的修复操作:
- 搭建Maven项目,引入15.3版本
org.openjdk.nashorn:nashorn-core依赖,配置maven-compiler-plugin指定编译目标为Java 11,搭配maven-dependency-plugin、maven-jar-plugin打包为可执行Jar - 代码层面放弃通过
javax.script.ScriptEngineManager获取引擎,改为直接实例化org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory获取脚本引擎,期望加载独立版Nashorn规避内置版本缺陷 - 尝试添加JVM启动参数
--module-path引入依赖包、--add-modules org.openjdk.nashorn加载独立模块
- 搭建Maven项目,引入15.3版本
- 验证结果:
- 使用Java 11.0.9 LTS编译打包运行,引擎信息打印为OpenJDK Nashorn 15.3,但仍抛出相同栈溢出错误
- 相同代码在移除内置Nashorn的Java 17环境运行无异常,确认Java 11环境实际仍加载了JDK内置Nashorn实现
根因
Java 11内置的Nashorn由引导类加载器加载,优先级高于classpath下的第三方依赖。即使直接实例化独立版的NashornScriptEngineFactory,其内部依赖的代码生成、字节码处理等内部工具类仍会被优先加载JDK内置版本,独立版中修复的递归栈溢出逻辑未实际生效。
修复方案(仅需Maven配置,无额外JVM参数要求)
通过maven-shade-plugin配置fatjar打包规则,将独立版Nashorn的类优先打入Jar包根路径,覆盖JDK内置类的加载优先级:
- 移除原有
maven-jar-plugin、maven-dependency-plugin组合的fatjar打包配置,替换为maven-shade-plugin配置:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.5.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <createDependencyReducedPom>false</createDependencyReducedPom> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <!-- 替换为自身项目的主类全限定名 --> <mainClass>com.example.YourMainClass</mainClass> </transformer> <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> </transformers> <filters> <filter> <artifact>*:*</artifact> <excludes> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> </configuration> </execution> </executions> </plugin>
- 保留原有
maven-compiler-plugin的Java 11编译配置,nashorn-core依赖保持默认compile作用域即可:
<dependency> <groupId>org.openjdk.nashorn</groupId> <artifactId>nashorn-core</artifactId> <version>15.3</version> </dependency>
- 代码层无需修改原有直接实例化
NashornScriptEngineFactory的逻辑,执行mvn clean package生成可执行Jar后,直接通过java -jar 生成的jar包名.jar启动即可。
验证方式
启动后可通过断点或日志打印LocalVariableTypesCalculator类的加载路径,确认该类来自Jar包内的独立版Nashorn而非JDK内置路径,再执行长逻辑表达式eval操作即可确认栈溢出问题已修复。
内容的提问来源于stack exchange,提问作者Senthuran Ambalavanar
相关产品推荐
相关产品推荐

