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
相关产品推荐
相关产品推荐

