在 Maven 中指定 Java 版本 - 属性和编译器插件之间的差异

新手上路,请多包涵

我对 Maven 不是很有经验,在尝试多模块项目时,我开始想知道如何为父 Maven pom 中的所有子模块指定 Java 版本。直到今天我只使用:

 <properties>
    <java.version>1.8</java.version>
</properties>

…但是在研究时我发现您还可以在 Maven 编译器插件中指定 Java 版本,如下所示:

 <plugins>
    <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>1.8</source>
            <target>1.8</target>
        </configuration>
    </plugin>
</plugins>

然后将其包装到插件管理标签中以启用子 poms 的使用。所以第一个问题是这样的:

在属性和 Maven 编译器插件中设置 Java 版本有什么区别?

我找不到明确的答案,但在研究过程中我发现您也可以通过这种方式指定 Java 版本:

 <properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

…这表明即使我没有明确声明它也存在编译器插件。运行 mvn package 输出

maven-compiler-plugin:3.1:compile (default-compile) @ testproj ---

…以及我没有声明的其他一些插件。

那么这些插件是 Maven pom 的默认隐藏部分吗?在属性和 Maven 插件配置元素中设置源/目标之间有什么区别吗?

其他一些问题是 - 应该使用哪种方式(如果它们不相等,何时使用)?哪一个最适合多模块项目,如果 pom 中指定的 Java 版本与 JAVA_HOME 中指定的版本不同,会发生什么?

原文由 Plebejusz 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 2.1k
2 个回答

如何指定JDK版本?

使用以下三种方式中的任何一种:(1) Spring Boot 功能,或将 Maven 编译器插件与 (2) source & target 或 (3) 与 release 一起使用.

弹簧靴

  1. <java.version> 未在 Maven 文档中引用。

这是 Spring Boot 的特殊性。

它允许将源和目标 java 版本设置为相同的版本,例如为两者指定 java 1.8: 1.8

如果您使用 Spring Boot,请随意使用它。

maven-compiler-pluginsource & target

  1. 使用 maven-compiler-pluginmaven.compiler.source / maven.compiler.target 属性是等效的。

那确实是:

 <plugins>
    <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>1.8</source>
            <target>1.8</target>
        </configuration>
    </plugin>
</plugins>

相当于:

 <properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

according to the Maven documentation of the compiler plugin since the <source> and the <target> elements in the compiler configuration use the properties maven.compiler.source and maven.compiler.target 如果它们被定义。

资源

Java 编译器的 -source 参数。

注意:自 3.8.0 起,默认值已从 1.5 更改为 1.6。自 3.9.0 起,默认值已从 1.6 更改为 1.7

默认值为:1.7。

用户属性是: maven.compiler.source

目标

Java 编译器的 -target 参数。

注意:自 3.8.0 起,默认值已从 1.5 更改为 1.6。自 3.9.0 起,默认值已从 1.6 更改为 1.7

默认值为: 1.6

用户属性是: maven.compiler.target

About the default values for source and target , note that since the 3.8.0 of the maven compiler, the default values have changed from 1.51.6

maven-compiler-pluginrelease 代替 source & target

  1. maven-compiler-plugin 3.6 及以后的版本提供了一种新的方式: org.apache.maven.plugins maven-compiler-plugin 3.8.0 9

您也可以声明:

 <properties>
    <maven.compiler.release>9</maven.compiler.release>
</properties>

但此时它不起作用,因为您使用的 maven-compiler-plugin 默认版本不依赖于足够新的版本。

Maven release 参数传达了 release :我们可以从 Java 9 传递的 新 JVM 标准选项

针对特定 VM 版本的公共、受支持和记录的 API 进行编译。

这种方式提供了一种标准方式来为 sourcetargetbootstrap JVM 选项指定相同的版本。

请注意,指定 bootstrap 是交叉编译的好习惯,如果您不进行交叉编译也不会受到伤害。


指定 JDK 版本的最佳方法是什么?

第一种方式( <java.version> )仅在使用 Spring Boot 时才允许。

对于 Java 8 及以下版本:

关于其他两种方法:评估 maven.compiler.source / maven.compiler.target 属性 使用 maven-compiler-plugin ,您可以使用其中一种。它没有改变任何事实,因为最终这两种解决方案依赖于相同的属性和相同的机制:maven 核心编译器插件。

好吧,如果您不需要在编译器插件中指定除 Java 版本之外的其他属性或行为,那么使用这种方式更有意义,因为这样更简洁:

 <properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

从 Java 9 开始:

release 参数(第三点)是一种强烈考虑是否要对源和目标使用相同版本的方法。

如果 JAVA_HOME 中的 JDK 与 pom.xml 中指定的版本不同,会发生什么情况?

如果 JAVA_HOME 引用的 JDK 与 pom 中指定的版本兼容,这不是问题,但为了确保更好的交叉编译兼容性,请考虑添加 bootstrap JVM 选项作为值 target 版本的 rt.jar 的路径。

需要考虑的重要一点是,Maven 配置中的 sourcetarget 版本不应优于 JAVA_HOME 引用的 JDK 版本。

较旧版本的 JDK 无法与较新版本一起编译,因为它不知道其规范。

根据使用的JDK获取源、目标和发行版支持的版本信息,请参考 java编译:源、目标和发行版支持的版本


如何处理JAVA_HOME引用的JDK与pom中指定的java目标和/或源版本不兼容的情况?

例如,如果您的 JAVA_HOME 指的是 JDK 1.7,并且您在 pom.xml 的编译器配置中指定 JDK 1.8 作为源和目标,这将是一个问题,因为如上所述,JDK 1.7 没有不知道如何编译。

从它的角度来看,它是一个未知的JDK版本,因为它是在它之后发布的。

在这种情况下,您应该配置 Maven 编译器插件以通过以下方式指定 JDK:

 <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <source>1.8</source>
        <target>1.8</target>
        <compilerVersion>1.8</compilerVersion>
        <fork>true</fork>
        <executable>D:\jdk1.8\bin\javac</executable>
    </configuration>
</plugin>

您可以在 带有 maven 编译器插件的示例中 获得更多详细信息。


它没有被问到,但可能更复杂的情况是您指定源而不是目标。它可能会根据源版本在目标中使用不同的版本。规则是特别的:您可以在 交叉编译选项部分 阅读它们。


为什么在执行 Maven package 目标时在输出中跟踪编译器插件,即使您没有在 pom.xml 中指定它?

为了编译你的代码并且更普遍地执行 Maven 目标所需的所有任务,Maven 需要工具。因此,它使用核心 Maven 插件(您可以通过其 groupId 识别核心 Maven 插件: org.apache.maven.plugins )来执行所需的任务:用于编译类的编译器插件,用于执行测试的测试插件,等等……所以,即使你不声明这些插件,它们也必然会执行 Maven 生命周期。

在 Maven 项目的根目录中,您可以运行命令: mvn help:effective-pom 以有效使用最终的 pom。在其他信息中,您可以看到 Maven 附加的插件(在您的 pom.xml 中指定或未指定)、使用的版本、它们的配置以及生命周期每个阶段的执行目标。

mvn help:effective-pom 命令的输出中,您可以在 <build><plugins> 元素中看到这些核心插件的声明,例如:

 ...
<plugin>
   <artifactId>maven-clean-plugin</artifactId>
   <version>2.5</version>
   <executions>
     <execution>
       <id>default-clean</id>
       <phase>clean</phase>
       <goals>
         <goal>clean</goal>
       </goals>
     </execution>
   </executions>
 </plugin>
 <plugin>
   <artifactId>maven-resources-plugin</artifactId>
   <version>2.6</version>
   <executions>
     <execution>
       <id>default-testResources</id>
       <phase>process-test-resources</phase>
       <goals>
         <goal>testResources</goal>
       </goals>
     </execution>
     <execution>
       <id>default-resources</id>
       <phase>process-resources</phase>
       <goals>
         <goal>resources</goal>
       </goals>
     </execution>
   </executions>
 </plugin>
 <plugin>
   <artifactId>maven-compiler-plugin</artifactId>
   <version>3.1</version>
   <executions>
     <execution>
       <id>default-compile</id>
       <phase>compile</phase>
       <goals>
         <goal>compile</goal>
       </goals>
     </execution>
     <execution>
       <id>default-testCompile</id>
       <phase>test-compile</phase>
       <goals>
         <goal>testCompile</goal>
       </goals>
     </execution>
   </executions>
 </plugin>
  ...

您可以 在 Maven 文档中的 Maven 生命周期介绍中 获得更多信息。

不过,当您想将这些插件配置为其他值作为默认值时(例如,当您在 pom.xml 中声明 maven-compiler 插件以调整要使用的 JDK 版本时,您可以声明这些插件)或当您想要添加一些在 Maven 生命周期中默认不使用的插件执行。

原文由 davidxxx 发布,翻译遵循 CC BY-SA 4.0 许可协议

上面的解决方案都没有立即对我有用。所以我遵循了以下步骤:

  1. 添加 pom.xml:
 <properties>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.source>1.8</maven.compiler.source>
</properties>

  1. 转到 Project Properties > Java Build Path ,然后删除指向 JRE1.5 的 JRE 系统库。

  2. 强制更新项目。

原文由 Sen 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题