Spring Boot jar包运行时InMemoryJavaCompiler编译依赖类失败求助
解决Spring Boot Jar启动时InMemoryJavaCompiler无法识别依赖类的问题
这个问题我之前也碰到过,核心原因是Spring Boot Jar的类加载机制和IDE启动时完全不一样:
问题根源
当你用java -jar启动Spring Boot应用时,所有依赖(包括你的业务实体项目)都被打包在BOOT-INF/lib目录下,Spring Boot会用自定义的LaunchedURLClassLoader来加载这些类。而InMemoryJavaCompiler默认使用的是系统类加载器(System ClassLoader),这个类加载器根本看不到BOOT-INF/lib里的内容,自然找不到你的BaseClass和Entity。
反观IntelliJ启动时,它是把所有项目的类和依赖都直接放到系统类路径里,系统类加载器能轻松找到这些类,所以编译一切正常。
解决方案
1. 让InMemoryJavaCompiler使用Spring Boot的应用类加载器
这是最简单有效的办法,在创建编译器实例时,指定它使用当前应用的类加载器:
// 获取Spring Boot的应用类加载器 ClassLoader appClassLoader = getClass().getClassLoader(); // 初始化编译器并绑定类加载器 InMemoryJavaCompiler compiler = InMemoryJavaCompiler.newInstance() .useClassloader(appClassLoader);
这样编译器就能通过应用类加载器访问到BOOT-INF/lib里的业务实体类了。
2. 手动添加依赖到编译器Classpath(备选方案)
如果第一种方法没生效,你可以手动把业务实体项目的Jar路径添加到编译器的Classpath中。借助应用类加载器获取所有依赖的URL,再逐个添加:
ClassLoader appClassLoader = getClass().getClassLoader(); InMemoryJavaCompiler compiler = InMemoryJavaCompiler.newInstance(); // 从应用类加载器中提取所有依赖URL if (appClassLoader instanceof URLClassLoader) { URL[] classpathUrls = ((URLClassLoader) appClassLoader).getURLs(); for (URL url : classpathUrls) { compiler.addClasspath(url.getPath()); } }
不过一般第一种方法就足够覆盖场景了。
3. 确认业务项目依赖配置正确
最后检查一下API项目的build.gradle,确保业务实体项目被正确声明为依赖:
dependencies { implementation project(':your-business-entity-module-name') // 其他Spring Boot依赖... }
这样bootJar任务才会把业务项目的Jar打包到BOOT-INF/lib目录下。
验证
修改后重新打包API项目:
./gradlew bootJar
然后用java -jar启动,再调用POST接口测试动态编译,应该就能正常通过了。
内容的提问来源于stack exchange,提问作者J L
相关产品推荐
相关产品推荐

