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

Ple*_*usz 150 java maven-3 maven maven-compiler-plugin

我对maven不太熟悉,在尝试使用多模块项目时,我开始想知道如何为父maven pom中的所有子模块指定java版本.直到今天我才使用:

<properties>
    <java.version>1.8</java.version>
</properties>
Run Code Online (Sandbox Code Playgroud)

但是在研究时我发现你也可以在maven编译器插件中指定java版本,就像那样:

<plugins>
    <plugin>    
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>1.8</source>
            <target>1.8</target>
        </configuration>
    </plugin>
</plugins>
Run Code Online (Sandbox Code Playgroud)

然后将其包装到插件管理标签中以启用子poms的使用.所以第一个问题是在属性和maven编译器插件中设置java版本什么区别?

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

<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>
Run Code Online (Sandbox Code Playgroud)

这表明编译器插件就在那里,即使我没有明确声明它.运行mvn包输出

maven-compiler-plugin:3.1:compile (default-compile) @ testproj ---
Run Code Online (Sandbox Code Playgroud)

和其他一些我没有声明的插件.那些插件默认是隐藏的maven pom的一部分吗?在属性和maven插件配置元素中设置源/目标是否有任何差异?

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

dav*_*xxx 249

如何指定JDK版本?

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

<properties>
     <java.version>1.8</java.version>
</properties>   
Run Code Online (Sandbox Code Playgroud)

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

2)使用maven-compiler-pluginor maven.compiler.source/ maven.compiler.targetproperties指定sourcetarget等效.

<plugins>
    <plugin>    
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>1.8</source>
            <target>1.8</target>
        </configuration>
    </plugin>
</plugins>
Run Code Online (Sandbox Code Playgroud)

<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>
Run Code Online (Sandbox Code Playgroud)

根据编译器插件Maven文档是等价的, 因为编译器配置中<source><target>元素和属性maven.compiler.source以及maven.compiler.target它们是否已定义.

资源

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

目标

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

关于默认值source,并 target请注意, 由于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>
Run Code Online (Sandbox Code Playgroud)

你也可以声明:

<properties>
    <maven.compiler.release>9</maven.compiler.release>
</properties>
Run Code Online (Sandbox Code Playgroud)

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

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

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

通过这种方式提供一种标准方法来指定相同的版本source,在targetbootstrapJVM选项.
请注意,指定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>
Run Code Online (Sandbox Code Playgroud)

从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>
Run Code Online (Sandbox Code Playgroud)

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


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


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

为了编译代码,更一般地说,为了执行maven目标所需的所有任务,Maven需要工具.因此,它使用核心Maven插件(您可以通过识别核心Maven插件的groupId: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>
  ...
Run Code Online (Sandbox Code Playgroud)

您可以在Maven文档中引入Maven生命周期中获得有关它的更多信息.

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

  • “*如果您的 JAVA_HOME 的 JDK 与 pom 中指定的版本兼容,这不是问题*”这不是(必然)正确的,请检查[this](http://stackoverflow.com/questions/35913775/maven -java-version-configuration-ignored-by-eclipse-idea) Stack Overflow 线程供参考 (2认同)
  • @Robin A. Meade感谢您的反馈.我使用弹簧靴,但我不知道.就个人而言,我发现它不够标准,无法使用或引用作为使用的东西.Spring引导提供了一些非常有趣的东西,但在某些情况下它的功能非常易于理解.覆盖标准maven属性的名称以不填充源和目标jdk似乎是一个坏主意,因为它只为应用程序执行一次.您失去了在应用程序中备用简单xml行的标准.哇 !真是个好主意...... (2认同)
  • 太棒了而且描述性很强。谢谢! (2认同)