我对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使用这个。第一个问题是:

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

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

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

...这表明编译器插件是存在的,即使我没有显式声明它。运行mvn包输出

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

...和其他一些我没有声明的插件。

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

其他一些问题是——应该用哪种方式(如果它们不相等,什么时候用)?哪一个是最好的多模块项目,如果Java版本指定的pom是不同的版本指向JAVA_HOME?


当前回答

如果您正在使用IntelliJ idea maven构建。

其他回答

如何指定JDK版本?

使用三种方式中的任何一种:(1)Spring Boot特性,或使用Maven编译器插件(2)源&目标或(3)发布。

春天的引导

< java。Maven文档中没有引用版本>。 它是Spring Boot的特性。 它允许将源java版本和目标java版本设置为相同的版本,例如为两者指定java 1.8: 1.8

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

maven-编译器插件与源和目标

使用maven-compiler-plugin或maven.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>

根据编译器插件的Maven文档 因为编译器配置中的<source>和<target>元素如果定义了,则使用maven.compiler.source和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。

关于源和目标的默认值,请注意 从maven编译器的3.8.0开始,默认值已经从1.5更改为1.6。

Maven-compiler-plugin with release而不是source & target

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

你也可以声明just:

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

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

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

针对公共的、受支持的和文档化的API进行编译 虚拟机版本。

这种方式提供了一种为源、目标和引导JVM选项指定相同版本的标准方法。 请注意,指定引导是交叉编译的一个很好的实践,如果不进行交叉编译,也不会造成伤害。


指定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:

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

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

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

需要考虑的一件重要事情是,Maven配置中的源版本和目标版本不应该优于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包目标执行时的输出中被跟踪,即使您没有在pom.xml中指定它?

To compile your code and more generally to perform all tasks required for a maven goal, Maven needs tools. So, it uses core Maven plugins (you recognize a core Maven plugin by its groupId : org.apache.maven.plugins) to do the required tasks : compiler plugin for compiling classes, test plugin for executing tests, and so for... So, even if you don't declare these plugins, they are bound to the execution of the Maven lifecycle. At the root dir of your Maven project, you can run the command : mvn help:effective-pom to get the final pom effectively used. You could see among other information, attached plugins by Maven (specified or not in your pom.xml), with the used version, their configuration and the executed goals for each phase of the lifecycle.

在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生命周期中默认不使用的插件执行时,您可以声明这些插件。

考虑另一种选择:

<properties>
    <javac.src.version>1.8</javac.src.version>
    <javac.target.version>1.8</javac.target.version>
</properties>

它应该与maven.compiler.source/maven.compiler.target相同,但上面的解决方案适用于我,否则第二个得到父规范(我有一个.pom的矩阵)

以上的解决方案都不适合我。所以我采取了以下步骤:

在pom.xml中添加:

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

进入“项目属性> Java构建路径”,然后删除JRE 指向JRE1.5的系统库。 Force更新了项目。

如果您正在使用IntelliJ idea maven构建。

下面的步骤对我来说很有魅力!所以想和大家分享一下。

这些是我在pom.xml文件中添加的用于基本项目的行。我使用的是Java 12(你可以替换你的11、10、1.8等)。

<properties>
    <maven.compiler.source>12</maven.compiler.source>
    <maven.compiler.target>12</maven.compiler.target>
</properties>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <release>12</release>
            </configuration>
        </plugin>
    </plugins>
</build>

更改pom文件后,请重新加载您的项目,以便IDE可以下载/获取该插件到项目中。(对于IntelijIDEA:右键单击pom.xml -> Go to maven -> Reload project)。

请确保在您的IDE中配置所需的版本。