Java 10迁移:JRE环境下能否加载jdk.compiler模块实现运行时编译?
解决方案:Java 10+ 迁移时在JRE环境加载编译器模块的问题
首先得明确:标准JRE运行时确实不包含jdk.compiler模块,所以直接通过--add-module参数加载是行不通的——这就是你遇到java.lang.module.FindException的核心原因,JRE的镜像里根本没有这个模块的内容。不过有几个可行的替代方案,我给你梳理一下:
方案1:改用JDK运行应用(最省心的选择)
Java 9之后,JDK和JRE的边界其实已经模糊了,JDK里的java命令完全可以替代JRE的启动器。如果你的用户环境能提供JDK,直接用JDK的java命令启动应用:
- 你可以直接调用
javax.tools.ToolProvider.getSystemJavaCompiler(),不需要再反射加载JavacTool,JDK默认会包含jdk.compiler模块,能正常返回编译器实例。 - 如果你是模块化应用,只需要在
module-info.java里加上requires jdk.compiler;即可;非模块化应用甚至不需要额外配置,直接调用就行。
方案2:定制包含jdk.compiler的自定义JRE
如果必须坚持用JRE运行,可以用JDK自带的jlink工具创建一个包含jdk.compiler模块的自定义轻量JRE,步骤大概是:
- 找到你的JDK安装目录(比如
$JAVA_HOME) - 执行命令:
这里jlink --module-path $JAVA_HOME/jmods --add-modules jdk.compiler,java.base --output custom-jrejdk.compiler依赖java.base等基础模块,jlink会自动处理依赖,你只需要明确指定核心模块即可。 - 让用户用这个
custom-jre/bin/java来启动你的应用,此时JRE环境里就包含了编译模块,你可以正常使用ToolProvider.getSystemJavaCompiler()或者反射加载JavacTool。
方案3:使用第三方Java编译器(不依赖系统JDK)
如果用户环境无法提供JDK,也不想定制JRE,那可以考虑集成第三方纯Java编译器,比如Eclipse JDT Core Compiler。这个编译器是Eclipse IDE的核心组件,完全用Java实现,可以直接打包到你的应用中:
- 在项目依赖中加入
org.eclipse.jdt:org.eclipse.jdt.core(Maven/Gradle均可) - 直接使用JDT的API编译代码片段,示例核心逻辑大致如下:
这个方案的优势是完全不依赖系统的JDK/JRE版本,兼容性更强,适合跨环境运行的应用。import org.eclipse.jdt.internal.compiler.Compiler; import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; import org.eclipse.jdt.internal.compiler.CompilerOptions; import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; // 配置编译器参数 CompilerOptions options = new CompilerOptions(); options.sourceLevel = CompilerOptions.VERSION_10; options.targetLevel = CompilerOptions.VERSION_10; // 初始化编译器实例并执行编译 Compiler compiler = new Compiler( null, // 自定义NameEnvironment DefaultErrorHandlingPolicies.exitOnFirstError(), options, null, // 自定义CompilerRequestor new DefaultProblemFactory() ); // 传入待编译的代码单元执行编译
最后补充:你之前依赖tools.jar的反射加载方式在Java 8之后就已不推荐,Java 9+的模块化系统彻底移除了这种“拆包加载”的模式,上面的方案都是更符合现代Java版本规范的做法。
内容的提问来源于stack exchange,提问作者rainbowgoblin
相关产品推荐
相关产品推荐

