【问题标题】:Compile Maven Module with Different Java Version使用不同的 Java 版本编译 Maven 模块
【发布时间】:2012-09-07 00:14:34
【问题描述】:

我的 maven 项目有几个模块:服务器、web 等。

我想在 Java 6 上构建除我的服务器模块之外的所有模块。对于服务器模块,我想用 Java 7 编译它。

下面是我的 pom.xml,但我认为如果我将其修改为 1.7,那么我的所有模块都将使用 Java 7 编译。另外,maven 是否使用 JAVA_HOME 环境变量来确定要使用哪个 Java 版本?

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
                        <version>2.3.2</version>
        <configuration>
            <source>1.6</source>
            <target>1.6</target>
            <memmax>2048m</memmax>
        </configuration>
    </plugin>

EDIT 另外,下面的输出是

maven --version

表示maven正在用1.7编译我的java代码?

vagrant@dev:~/bin/apache-tomcat-7.0.29/bin$ mvn --version
Apache Maven 3.0.4 (r1232337; 2012-01-17 08:44:56+0000)
Maven home: /home/vagrant/bin/apache-maven-3.0.4
Java version: 1.7.0_07, vendor: Oracle Corporation
Java home: /home/vagrant/bin/jdk1.7.0_07/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "3.2.0-23-generic", arch: "amd64", family: "unix"

谢谢, 凯文

【问题讨论】:

    标签: maven


    【解决方案1】:

    在你的顶级 pom 上使用 JDK6 的设置,它将被所有模块继承,并用不同的配置为你的服务器 pom 覆盖它。

    至于JDK的路径,可以指定,看这里:http://maven.apache.org/plugins/maven-compiler-plugin/examples/compile-using-different-jdk.html

    【讨论】:

    • 基于我在原始帖子中包含的 maven --version 输出,这是否意味着 mvn 正在使用 1.7 进行编译?
    • 根据您的输出,您将使用 jdk 1.7 编译您的应用程序,但您的代码将编译为 jdk 1.6(或更高版本),这可以满足您的需要。
    • 请解释“mvn --version”输出与我的 pom.xml 中的 值的意义。如果我想只用 1.7 编译,那是否意味着我需要将 更改为 1.7?
    • mvn --version 只是让你看到当前正在使用的环境。关于源和目标参数,它们将指定如何使用 javac 工具设置相同的参数:请参阅以下链接中对这些参数的描述:http://docs.oracle.com/javase/6/docs/technotes/tools/windows/javac.html
    • 所以在您的上下文中,您告诉 JDK 1.7 首先确保源代码仅包含 1.6 VM 和/或更低版本可用的功能,然后告诉它生成与JVM 1.6 或以上。
    【解决方案2】:

    有许多技巧可以使用与运行 Maven 不同的 JDK 版本来编译源代码,例如,您可以使用类似的东西

    <project>
      [...]
      <build>
        [...]
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.5.1</version>
            <configuration>
              <executable><!-- path-to-javac --></executable>
            </configuration>
          </plugin>
        </plugins>
        [...]
      </build>
      [...] 
    </project>
    

    这种方法的问题是您现在已经将 JDK 的路径硬编码到您的 POM 中。 您的机器上一切都会正常工作,但是当您因为 HDD 故障而必须重建机器时,或者当您想在另一台机器上构建时,您将被卡住,因为路径很可能不会匹配。

    处理此问题的正确最佳实践方法是通过Toolchains。这将看到您创建一个~/.m2/toolchains.xml 文件,该文件描述系统中每个不同工具链的位置。然后可以通过Maven Toolchains Plugin应用JDK的版本,例如

    <plugins>
     ...
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-toolchains-plugin</artifactId>
        <version>1.0</version>
        <executions> 
          <execution>
            <phase>validate</phase>
            <goals>
              <goal>toolchain</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <toolchains>
            <jdk>
              <version>1.6</version>
            </jdk>
          </toolchains>
        </configuration>
      </plugin>
      ...
    </plugins>
    

    接下来的事情是,您并不像您想象的那样经常需要它。例如,通过使用 sourcetarget 值,您可以为您所针对的 JRE 生成正确的字节码……您将遇到的唯一问题是使用 JRE 1.7 中的新方法。 . 这就是Mojo's Animal Sniffer Plugin 的用武之地。Animal Sniffer 可用于确保您仅使用目标 JRE 的方法。普遍的社区共识是,在 Maven 编译器插件配置中使用 sourcetarget 配置选项,再加上 Mojo 的动物嗅探器的使用,实际上消除了在编译器端对工具链的需求......万事俱备,仍然需要工具链......我有一些边缘情况需要更新编译器插件和工具链插件来处理,但实际上你不会遇到这些边缘情况;-)

    只是为了确保您的原始问题得到完全回答(因为上面回答了您想问的问题 - 而不是您提出的问题)

    目前您使用 JDK 1.7 进行编译但是根据您使用的 Maven 编译器插件的版本,您可能使用 &lt;source&gt;1.4&lt;/source&gt;&lt;target&gt;1.4&lt;/target&gt;&lt;source&gt;1.5&lt;/source&gt;&lt;target&gt;1.5&lt;/target&gt; 进行编译,除非您更改了在 pom.xml 中配置 Maven 编译器插件。这将决定您可以使用哪些语言功能,而不是哪些类...因此您将生成适用于 JRE 1.7 的代码,并且如果您没有使用自 1.4/1.5 以来引入的任何新类/方法(例如String.isEmpty())也应该在 JRE 1.4/1.5 上工作......确定它是否适用于这样一个旧 JVM 的唯一方法是:在旧 JVM 上运行它或使用 Animal Sniffer。

    【讨论】:

    • 就像在你的 pom 中添加 maven-compiler-plugin 并添加 配置选项添加一个小捷径,就是设置编译器插件检查的一些属性' 1.7${java.version}${java.version}'
    • 编辑此最佳答案以澄清正确交叉编译的新最佳实践是使用 javac --release 标志是否有意义(请参阅stackoverflow.com/a/43103038)?它在配置方面更容易,速度更快(无需为每个模块分叉进程),适用于 Java 7+。工具链可能仍然有用,例如,如果还需要在目标 JVM 上运行测试或为古老的 Java(6 或更早版本)进行编译。
    【解决方案3】:

    Maven 工具链

    要使用多个 Java 版本,您需要使用 Maven Toolchains,这需要您在您的 ~/.m2 Maven 文件夹中创建一个 toolchains.xml 文件,其中包含您机器上安装的所有 Java 版本:

    <toolchains>
      <toolchain>
        <type>jdk</type>
        <provides>
          <id>Java13</id>
          <version>13</version>
        </provides>
        <configuration>
          <jdkHome>${env.JAVA_HOME_13}</jdkHome>
        </configuration>
      </toolchain>
      <toolchain>
        <type>jdk</type>
        <provides>
          <id>Java9</id>
          <version>9</version>
        </provides>
        <configuration>
          <jdkHome>${env.JAVA_HOME_9}</jdkHome>
        </configuration>
      </toolchain>
      <toolchain>
        <type>jdk</type>
        <provides>
          <id>Java8</id>
          <version>8</version>
        </provides>
        <configuration>
          <jdkHome>${env.JAVA_HOME_8}</jdkHome>
        </configuration>
      </toolchain>
      <toolchain>
        <type>jdk</type>
        <provides>
          <id>Java7</id>
          <version>7</version>
        </provides>
        <configuration>
          <jdkHome>${env.JAVA_HOME_7}</jdkHome>
        </configuration>
      </toolchain>
      <toolchain>
        <type>jdk</type>
        <provides>
          <id>Java6</id>
          <version>6</version>
        </provides>
        <configuration>
          <jdkHome>${env.JAVA_HOME_6}</jdkHome>
        </configuration>
      </toolchain>
    </toolchains>
    

    JAVA_HOME_13JAVA_HOME_9JAVA_HOME_8JAVA_HOME_7JAVA_HOME_6 环境变量配置为引用相关 Java 版本的安装路径。

    FlexyPool 父 pom.xml 配置文件

    FlexyPool项目的父pom.xmlMaven配置文件定义了全局Java版本设置

    <properties>
        <jdk.version>8</jdk.version>
        ...
    </properties>
    

    现在,我们需要指示编译器和测试插件都使用配置的 java 版本。

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-toolchains-plugin</artifactId>
                <version>1.1</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>toolchain</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <toolchains>
                        <jdk>
                            <version>${jdk.version}</version>
                        </jdk>
                    </toolchains>
                </configuration>
            </plugin>
            
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven-compiler-plugin.version}</version>
                <configuration>
                    <source>${jdk.version}</source>
                    <target>${jdk.version}</target>
                    <showDeprecation>true</showDeprecation>
                    <showWarnings>true</showWarnings>
                </configuration>
            </plugin>
            
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${maven-surefire-plugin.version}</version>
            </plugin>
        </plugins>
    </build>
    

    FlexyPool 子 Maven 模块 pom.xml 使用不同的 Java 版本

    需要不同Java版本的flexy-pool-core-java9子Maven模块只需要覆盖默认的jdk.versionMaven属性即可:

    <properties>
        <jdk.version>9</jdk.version>
    </properties>
    

    就是这样,我们现在可以使用自己的最低可行 Java 版本构建每个模块。

    【讨论】:

    • 环境变量是going away soon,但在$M2_HOME/conf/settings.xml (source) 中仍受支持
    • 感谢您的提示。
    猜你喜欢
    • 2016-09-24
    • 2016-05-14
    • 2021-04-06
    • 1970-01-01
    • 1970-01-01
    • 2012-02-24
    • 1970-01-01
    • 2019-07-28
    相关资源
    最近更新 更多