You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java程序运行时编译Scala代码的脚本引擎及类加载问题

解决Java集成Scala脚本引擎的打包及动态依赖问题

一、打包Jar后Scala ScriptEngine获取失败/编译器无法读取Jar的问题

问题原因

  • 打包时丢失Scala脚本引擎的SPI配置文件,导致ScriptEngineManager无法识别Scala引擎
  • Fat Jar打包未合并META-INF服务配置,或Scala编译器/类库的类文件被损坏
  • 类加载器无法正确加载Scala相关依赖类

解决步骤

  1. 补全SPI配置文件
    在项目src/main/resources/META-INF/services目录下创建javax.script.ScriptEngineFactory文件,写入:
scala.tools.nsc.interpreter.IMain$ScriptEngineFactory
  1. Fat Jar打包合并服务配置
  • Maven Shade插件配置:
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.4.1</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                </transformers>
            </configuration>
        </execution>
    </executions>
</plugin>
  • Gradle Shadow插件配置:
shadowJar {
    mergeServiceFiles()
}
  1. 手动初始化ToolBox时指定类路径
    放弃ScriptEngineManager,直接创建实例时明确设置类路径:
import scala.tools.nsc.Settings;
import scala.tools.reflect.ToolBox;
import scala.tools.reflect.ToolBoxFactory;

Settings settings = new Settings();
// 追加基础类路径及Scala依赖Jar
settings.classpath().append(System.getProperty("java.class.path"));
settings.classpath().append("/path/to/scala-library.jar");
settings.classpath().append("/path/to/scala-compiler.jar");

ToolBox toolBox = new ToolBoxFactory().create(settings);

二、动态添加依赖仅首次eval前生效的问题

问题原因

Scala的ToolBox/IMain在首次执行eval时会固化编译器的类路径,初始化完成后无法修改已加载的类路径配置。

解决步骤

  1. 添加新依赖后重新创建ToolBox
    这是最直接的方案,每次更新依赖后基于新的类路径实例化ToolBox:
import scala.tools.nsc.Settings;
import scala.tools.reflect.ToolBox;
import scala.tools.reflect.ToolBoxFactory;
import java.util.ArrayList;
import java.util.List;

public class ScalaScriptRunner {
    private List<String> dynamicJars = new ArrayList<>();

    public void addJar(String jarPath) {
        dynamicJars.add(jarPath);
    }

    public Object runScript(String code) {
        Settings settings = new Settings();
        // 加载基础类路径
        settings.classpath().append(System.getProperty("java.class.path"));
        // 追加动态添加的Jar
        for (String jar : dynamicJars) {
            settings.classpath().append(jar);
        }
        ToolBox toolBox = new ToolBoxFactory().create(settings);
        return toolBox.eval(toolBox.parse(code));
    }
}
  1. 优化方案:缓存不同依赖组合的ToolBox
    如果需要频繁切换依赖组,可以为不同的依赖集合创建独立的ToolBox实例并缓存,减少重复初始化的开销。

内容的提问来源于stack exchange,提问作者evgrot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 15:01:10