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

Spring Boot应用动态编译含依赖Java代码失败排查

问题原因

Janino的SimpleCompiler仅设置父类加载器不足以让编译器在编译时找到依赖类的定义,它需要显式指定完整的类路径——包括当前Spring Boot应用的编译类目录和外部依赖jar包(如data-model.jar)的路径。父类加载器主要用于运行时类加载,而非编译阶段的依赖查找。

解决方案

1. 构建完整类路径

添加方法获取当前应用的全部类路径,包含自身编译类目录和所有依赖jar包:

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;

private String getFullClasspath() throws IOException {
    StringBuilder classpathBuilder = new StringBuilder();
    ClassLoader currentClassLoader = getClass().getClassLoader();

    // 添加当前应用的classes目录(Spring Boot fat jar下为BOOT-INF/classes)
    URL appClassesUrl = currentClassLoader.getResource("");
    if (appClassesUrl != null) {
        classpathBuilder.append(new File(appClassesUrl.getFile()).getAbsolutePath());
        classpathBuilder.append(File.pathSeparator);
    }

    // 添加所有依赖jar包(包括data-model.jar)
    if (currentClassLoader instanceof URLClassLoader) {
        URL[] dependencyUrls = ((URLClassLoader) currentClassLoader).getURLs();
        for (URL url : dependencyUrls) {
            classpathBuilder.append(new File(url.getFile()).getAbsolutePath());
            classpathBuilder.append(File.pathSeparator);
        }
    }

    // 移除末尾多余的路径分隔符
    if (classpathBuilder.length() > 0) {
        classpathBuilder.setLength(classpathBuilder.length() - 1);
    }

    return classpathBuilder.toString();
}

2. 配置SimpleCompiler的类路径

在compileJavaCode方法中添加类路径设置,这是解决依赖找不到问题的关键:

private Class<?> compileJavaCode(String javaCode) throws Exception {
    SimpleCompiler compiler = new SimpleCompiler();
    compiler.setParentClassLoader(getClass().getClassLoader());
    
    // 关键步骤:设置完整类路径
    compiler.setClassPath(getFullClasspath());

    ByteArrayOutputStream errStream = new ByteArrayOutputStream();
    compiler.setCompileErrorHandler(new ErrorHandler() {
        @Override
        public void handleError(String message, Location location) {
            log.error("Compilation error: {}  Line: {}", message, location.getLineNumber());
            try {
                errStream.write(("Compilation error: " + message + "\n").getBytes());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    });

    compiler.cook(javaCode);
    // 返回编译后的目标类
    return compiler.getClassLoader().loadClass("ai.myapps.service.triggers.MyDynamicCode");
}

3. 额外检查项

  • 确保动态代码中引用的类(如WebInterface、DynamicCode)是public访问权限,否则编译时会出现无法访问的错误。
  • 如果Spring Boot使用默认的fat jar结构,上述方法已自动处理BOOT-INF/classes和BOOT-INF/lib下的依赖,无需额外配置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 16:42:41