1. 问题现象
在 IDEA 中执行 Maven compile 时,项目编译失败。项目是一个 Maven + Scala + Java 混合项目,使用的是 scala-maven-plugin 编译 Scala 代码。
执行命令中可以看到当前使用的是 JDK 1.8:
D:\ProgramFiles\Java\jdk1.8.0_341\bin\java.exe
Maven 使用的是:
D:\ProgramFiles\apache-maven-3.6.1
编译过程中先出现了一个 Maven settings 警告:
[WARNING] Some problems were encountered while building the effective settings
[WARNING] Unrecognised tag: 'blocked'
@ D:\ProgramFiles\apache-maven-3.6.1\conf\settings.xml, line 216, column 16
后面执行到 scala-maven-plugin 时失败:
[INFO] --- scala-maven-plugin:4.5.0:compile (default) @ wangba_archival ---
[INFO] Using incremental compilation using Mixed compile order
[INFO] compiling 32 Scala sources and 2 Java sources to D:\Documents\work\codes\dgzwb-archival\target\classes ...
[WARNING] javac exited with exit code -1
[ERROR] ## Exception when compiling 34 sources to D:\Documents\work\codes\dgzwb-archival\target\classes
java.io.IOException: Cannot run program "D:\ProgramFiles\Java\jdk1.8.0_341\jre\bin\javac"
(in directory "D:\Documents\work\codes\dgzwb-archival"):
CreateProcess error=2, 系统找不到指定的文件。
最关键的错误是这一句:
Cannot run program "D:\ProgramFiles\Java\jdk1.8.0_341\jre\bin\javac"
CreateProcess error=2, 系统找不到指定的文件。
2. 先判断哪个是主因
这段日志里有两个问题:
- Maven 提示
Unrecognised tag: 'blocked' - Scala 编译时报
jre\bin\javac找不到
真正导致构建失败的是第二个问题,也就是 javac 找不到。
Unrecognised tag: 'blocked' 只是 Maven 读取 settings.xml 时的警告。Maven 3.8.1 开始在 mirror 配置中增加了 <blocked> 参数,用来默认阻止外部 HTTP 仓库。当前环境使用的是 Maven 3.6.1,这个版本不认识 <blocked> 标签,所以会打印警告。
这个警告需要处理,但它不是这次 BUILD FAILURE 的直接原因。
3. 为什么会去找 jre\bin\javac
Oracle 的 Java 8 文档中说明,JDK 包含编译器、调试器等开发工具,而 JRE 主要用于运行 Java 程序。javac 属于 JDK 的编译工具。
正常情况下,javac 应该在:
D:\ProgramFiles\Java\jdk1.8.0_341\bin\javac.exe
而不是:
D:\ProgramFiles\Java\jdk1.8.0_341\jre\bin\javac
因为 JRE 目录下面通常只有运行环境,不应该依赖它提供 javac。
这次异常中,Maven 启动时确实使用了:
D:\ProgramFiles\Java\jdk1.8.0_341\bin\java.exe
但是 scala-maven-plugin 在增量编译 Java 源码时,最终却调用到了:
D:\ProgramFiles\Java\jdk1.8.0_341\jre\bin\javac
说明插件内部或当前环境推导出来的 Java Home 路径不正确,把 jre 当成了查找 javac 的位置。
4. 为什么 Scala 项目会调用 javac
日志中有一行很关键:
Using incremental compilation using Mixed compile order
这说明当前项目是 Scala 和 Java 混合编译。scala-maven-plugin 不只是编译 Scala 文件,还会配合 Zinc 增量编译器处理 Java 源码。
日志里也明确写了:
compiling 32 Scala sources and 2 Java sources
所以即使项目看起来主要是 Scala,只要里面有 Java 源码,或者 Scala 编译过程中需要 Java 编译器参与,最终仍然需要 javac。
如果当前环境里找不到正确的 javac,Scala 编译也会失败。
5. 解决方案一:检查 IDEA 的 Maven JDK
如果是在 IDEA 里执行 Maven,先检查 IDEA 的 Maven JDK。
路径一般是:
File -> Settings -> Build, Execution, Deployment -> Build Tools -> Maven -> Runner
重点检查:
JRE
这里不要选择 JRE,也不要选择项目里某个不完整的 Java 运行环境,应该选择完整的 JDK,例如:
D:\ProgramFiles\Java\jdk1.8.0_341
如果这里选成了:
D:\ProgramFiles\Java\jdk1.8.0_341\jre
就很容易出现 jre\bin\javac 找不到的问题。
6. 解决方案二:检查 JAVA_HOME 和 Path
在命令行中检查:
echo %JAVA_HOME%
期望输出是 JDK 根目录:
D:\ProgramFiles\Java\jdk1.8.0_341
再检查 javac 是否能直接执行:
javac -version
如果提示找不到 javac,需要检查系统环境变量:
JAVA_HOME=D:\ProgramFiles\Java\jdk1.8.0_341
Path=%JAVA_HOME%\bin
注意不要写成:
JAVA_HOME=D:\ProgramFiles\Java\jdk1.8.0_341\jre
JAVA_HOME 应该指向 JDK 根目录,而不是 JRE 目录。
7. 解决方案三:在 scala-maven-plugin 中显式指定 javac
如果 IDEA 和环境变量都没有问题,但 scala-maven-plugin 仍然推导错了路径,可以在插件配置中显式指定 javac。
例如:
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>4.5.0</version>
<configuration>
<scalaVersion>2.11.8</scalaVersion>
<recompileMode>incremental</recompileMode>
<compileOrder>Mixed</compileOrder>
<javacArgs>
<javacArg>-source</javacArg>
<javacArg>1.8</javacArg>
<javacArg>-target</javacArg>
<javacArg>1.8</javacArg>
</javacArgs>
</configuration>
</plugin>
如果项目中使用了 Maven Toolchains,也可以统一指定 JDK:
<toolchain>
<type>jdk</type>
<provides>
<version>1.8</version>
<vendor>oracle</vendor>
</provides>
<configuration>
<jdkHome>D:\ProgramFiles\Java\jdk1.8.0_341</jdkHome>
</configuration>
</toolchain>
老项目里更常见的处理方式还是先保证 IDEA、Maven、命令行使用的是同一个 JDK。
8. 处理 settings.xml 中的 blocked 警告
日志中还有一个警告:
Unrecognised tag: 'blocked'
这个一般是因为 settings.xml 中有类似配置:
<mirror>
<id>maven-default-http-blocker</id>
<mirrorOf>external:http:*</mirrorOf>
<name>Pseudo repository to mirror external repositories initially using HTTP.</name>
<url>http://0.0.0.0/</url>
<blocked>true</blocked>
</mirror>
<blocked> 是 Maven 3.8.1 之后用于阻止外部 HTTP 仓库的配置。当前日志中的 Maven 是 3.6.1,所以它不认识这个标签。
解决方式有两种:
- 升级 Maven 到 3.8.1 或更高版本。
- 如果必须使用 Maven 3.6.1,就从
settings.xml中删除不兼容的<blocked>配置。
如果公司内网仓库仍然是 HTTP 地址,不建议简单删除后不管。更稳妥的方式是把仓库地址改成 HTTPS,或者配置公司内部仓库代理。
9. 建议排查顺序
遇到这类问题,可以按下面顺序排查:
| 步骤 | 检查内容 | 说明 |
|---|---|---|
| 1 | 看最终失败原因 | 本例是 Cannot run program ... jre\bin\javac |
| 2 | 检查 JDK 是否完整 | 确认 bin\javac.exe 存在 |
| 3 | 检查 IDEA Maven Runner | 确认 JRE 选择的是 JDK 根目录 |
| 4 | 检查 JAVA_HOME |
不要指向 jre |
| 5 | 命令行执行 javac -version |
确认系统能找到 javac |
| 6 | 处理 Maven settings 警告 | Maven 3.6.1 不支持 <blocked> |
10. 总结
这次异常的直接原因是:
scala-maven-plugin 在混合编译 Scala 和 Java 源码时,需要调用 javac,
但是最终查找到了 jre\bin\javac,而这个路径下没有 javac。
真正的修复方向是:
让 IDEA、Maven、JAVA_HOME 都指向完整 JDK,而不是 JRE。
同时,settings.xml 中的 <blocked> 警告也应该顺手处理。它不是这次编译失败的直接原因,但说明 Maven 版本和配置文件格式不匹配,后面下载依赖时也可能继续引发问题。