在 maven 中指定 Java 版本 - 属性和编译器插件之间的差异弹簧靴 maven-compiler-plugin跟source & target maven-compiler-plugin用而不是releasesource & target

2022-08-31 05:33:56

我对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


答案 1

如何指定 JDK 版本?

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

弹簧靴

  1. <java.version>在 Maven 文档中未引用。
    这是一个弹簧靴特异性。
    它允许将源和目标java版本设置为相同的版本,例如这个版本,以便为两者指定java 1.8:

    1.8

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

maven-compiler-pluginsource & target

  1. 使用 or / 属性是等效的。maven-compiler-pluginmaven.compiler.sourcemaven.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>

根据编译器插件的 Maven 文档,因为 编译器配置中的 和 元素使用属性,并且如果定义了属性。<source><target>maven.compiler.sourcemaven.compiler.target

Java 编译器的参数。
注意:自 3.8.0 起,默认值已从 1.5 更改为 1.6。自 3.9.0 起,默认值已从 1.6 更改为 1.7
默认值为:1.7。
用户属性为:。-sourcemaven.compiler.source

目标

Java 编译器的参数。
注意:自 3.8.0 起,默认值已从 1.5 更改为 1.6。自 3.9.0 起,默认值已从 1.6 更改为 1.7
默认值为:。
用户属性为:。-target1.6maven.compiler.target

关于 和 的默认值,请注意,自 maven 编译器的 3.8.0 以来,默认值已从 1.5 更改为 1.6sourcetarget

maven-compiler-plugin用而不是releasesource & 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参数传达了:一个新的JVM标准选项,我们可以从Java 9传递:releaserelease

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

这种方式提供了一种标准方法,用于为 、 和 JVM 选项指定相同的版本。
请注意,指定 是交叉编译的良好做法,如果您不进行交叉编译,也不会有什么坏处。sourcetargetbootstrapbootstrap


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

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

对于 Java 8 及更低版本:

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

好吧,如果您不需要在编译器插件中指定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中指定的版本之间不同,会发生什么情况?

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

需要考虑的重要一点是,Maven 配置中的 和 版本不应优于 .
旧版本的JDK无法使用更新的版本进行编译,因为它不知道其规范。sourcetargetJAVA_HOME

要根据使用的JDK获取有关源,目标和发布支持版本的信息,请参阅java编译:源,目标和发布支持的版本


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

例如,如果您引用了 JDK 1.7,而您在 pom.xml 的编译器配置中指定了 JDK 1.8 作为源和目标,那么这将是一个问题,因为如前所述,JDK 1.7 不知道如何编译。
从它的角度来看,它是一个未知的JDK版本,因为它是在它之后发布的。
在这种情况下,您应该配置Maven编译器插件以以这种方式指定JDK:JAVA_HOME

<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 目标时会在输出中跟踪编译器插件,即使您没有在 pom.xml 中指定它?

为了编译代码,更一般地执行 Maven 目标所需的所有任务,Maven 需要工具。因此,它使用核心Maven插件(您可以通过其识别核心Maven插件:)来执行所需的任务:用于编译类的编译器插件,用于执行测试的测试插件,等等...因此,即使您不声明这些插件,它们也绑定到Maven生命周期的执行。
在 Maven 项目的根目录下,您可以运行以下命令 :以有效使用最终的 pom。您可以在其他信息中看到Maven附加的插件(在您的pom.xml中指定或未指定),以及使用的版本,它们的配置以及生命周期每个阶段的执行目标。groupIdorg.apache.maven.pluginsmvn help:effective-pom

在命令的输出中,您可以看到元素中这些核心插件的声明,例如: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 lifeycle 介绍中了解有关它的更多信息。

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


答案 2

上述解决方案都没有立即为我工作。所以我按照以下步骤操作:

  1. 加入pom.xml:
<properties>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.source>1.8</maven.compiler.source>
</properties>
  1. 转到>,然后删除指向 的 JRE 系统库。Project PropertiesJava Build PathJRE1.5

  2. 强制更新项目。


推荐