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


177

我对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用法。因此,第一个问题是beetwen在属性和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的默认隐藏部分吗?beetwen在属性和maven插件配置元素中设置源/目标是否有任何区别?

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

Answers:


288

如何指定JDK版本?

1)<java.version>在Maven文档中未引用。
这是Spring Boot的特性。
它允许将源Java版本和目标Java版本设置为同一版本,例如,为两者指定Java 1.8:

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

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

2)使用maven-compiler-pluginmaven.compiler.source/ maven.compiler.target属性指定sourcetarget等效。

<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是否已定义属性。

资源

-sourceJava编译器的参数。
默认值为:1.6
用户属性是:maven.compiler.source

目标

-targetJava编译器的参数。
默认值为:1.6
用户属性是:maven.compiler.target

关于默认值sourcetarget,注意, 因为3.8.0maven的编译器,默认值已经从改变1.51.6

3)maven-compiler-plugin 3.6和更高版本提供了一种新方法:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.0</version>
    <configuration>
        <release>9</release>
    </configuration>
</plugin>

您也可以只声明:

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

但是,由于maven-compiler-plugin您使用的默认版本不依赖最新的版本,因此目前无法使用。

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

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

这种方式提供了一种标准方法,可以为sourcetargetbootstrapJVM选项指定相同的版本。
请注意,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中指定的JDK之间的版本不同,会发生什么?

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

要考虑的重要事项是Maven配置中的sourcetarget版本不应优于所引用的JDK版本JAVA_HOME
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编译器插件的示例中获得更多详细信息。


不需要询问,但是可能更复杂的情况是指定源而不是目标。根据源版本,它可能在目标中使用其他版本。规则很特别:您可以在“交叉编译选项”部分中阅读它们。


为什么package即使未在pom.xml中指定编译器插件,在执行Maven 目标时仍会在输出中跟踪该编译器插件?

为了编译您的代码,并且更一般地执行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 lifeycle时,您可以了解有关它的更多信息。

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


感谢您的广泛解释,现在对我来说更清楚了。同样关于<java.version>-我已经在一些代码片段中看到了这一点,也许那是一些自定义属性,我错误地认为这是声明Java版本的方法,<maven.compiler.x>从现在开始将坚持使用该属性。
Plebejusz

欣慰地欢迎您:)最初,我并不是打算这么多地发展,但是当我开始时,我无法停止:)对于<java.version>`很有可能。再见!
davidxxx '16

1
如果您的JAVA_HOME的JDK与pom中的指定版本兼容,这不是问题”(不是),请检查 Stack Overflow线程以供参考
A_Di-Matteo

2
@Robin A. Meade感谢您的反馈。我使用弹簧靴,但我不知道。就我个人而言,我发现它不够标准,无法被使用或引用为使用的东西。Spring Boot提供了一些非常有趣的东西,但是在某些情况下,它的功能是非常可争议的。覆盖标准Maven属性的名称以不同时填充源jdk和目标jdk似乎是一个坏主意,因为它对应用程序执行了一次。您失去了在应用程序中保留一条简单xml行的标准。哇 !什么主意...
davidxxx

1
@ MasterJoe2您可以在10版本的官方javac文档中找到它:docs.oracle.com/javase/10/tools/javac.htm#JSWOR627。我有分裂这个问题的答案在为变得太大两个部分,你也可以看看这个:stackoverflow.com/questions/51692748/...
davidxxx

3

上述解决方案都没有立即对我起作用。所以我做了以下事情:

  1. 添加

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

    在pom.xml中

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

  3. 强制更新项目。


您为Java 10及更高版本指定哪个版本?是10还是1.10?
MasterJoe2

来自Java 9及更高版本的@ MasterJoe2您需要按原样编写版本号(<version> 10 </ version>),而对于以下版本,则必须在版本之前添加1.(<version> 1.5 </ version>)
ikbel benab

0

考虑替代方案:

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

应该是一样的,maven.compiler.source/maven.compiler.target但是上面的解决方案对我有用,否则第二个解决方案会得到父级规范(我的Matrioska为.pom)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.