【问题标题】:How to build two different EAR in maven for with same java files in JAVA 6 and JAVA 11 with different jars for both java version?如何在 Maven 中使用相同的 Java 文件在 JAVA 6 和 JAVA 11 中构建两个不同的 EAR,并为两个 Java 版本使用不同的 jar?
【发布时间】:2020-11-19 06:34:15
【问题描述】:

我的项目目前在 ant 中,我们想迁移到 maven。 我们必须为不同的服务器同时支持 java 6 和 java 11 构建(我们的代码库与 java 6 及更高版本兼容)。 Java 6 使用旧的 jar 文件,而 Java 11 有新的 jar 文件。 我们想用 java 6 和 11 用他们自己的一组 jar 编译项目。 (最终构建为两个不同的 EAR) 是否有可能在 Maven 中实现这一点,如果可以,那么如何实现?

编辑:为了清楚起见,我没有需要 java 7 及更高版本才能编译的代码。我的代码库如果与 java 6 及更高版本完全兼容。我只需要使用具有较新依赖项的 java 11 对其进行编译,以便在较新版本的服务器上运行它,同时为旧服务器支持 java 6,因此一个 EAR 使用 java 6,另一个使用 java 11。我们最终将只支持 java 11当我们所有的客户都转移到新服务器时。

【问题讨论】:

    标签: java maven ear


    【解决方案1】:

    我会选择一个多模块项目,其中包含用于两个 EAR 的两个模块,以及用于您要构建的 JAR 的额外模块。

    然后您可以在一个 EAR 中将 Java 版本设置为 6,在另一个 EAR 中设置为 11。

    【讨论】:

    • 只设置 EAR 的版本是不够的。相反,需要两次完全独立的编译运行。 Java 11 编译/自动创建 modules-info.java 可能会在 Java 6 EAR 包含它时中断类加载。该问题还概述了不同的库。所以这需要复杂的设置。我会完全分离两个代码库。在依赖地狱中保持安全。
    • @motzmann 如果您在多模块项目中有两个模块,则会自动分别编译它们。它们也可以有不同的依赖关系。抱歉,motzmann,我还不明白你的意思。
    • @motzmann Java 11 可以自动创建 modules-info.java 吗?
    • JDK9+ 只有在您手动创建模块信息时才会自动创建它……除此之外,我怀疑您是否可以基于库使其工作,但这是另一回事……
    • @ThorbjørnRavnAndersen 不,它不会自动创建一个。但例如,我的 IDE 建议这样做并预先填写一些要求行。由于我对 pom.xml/ 负责的环境一无所知,我假设最坏的情况:它突然出现,编译良好并破坏了生产中的所有内容。
    【解决方案2】:

    首先,您需要不同的编译器。向后兼容性存在限制。据我所知,Oracle JDK 支持当前的减两个主要版本。因此 JDK 11 javac 可以编译 JDK 8 incl。因此,我假设第一个 sn-p 类似于:

    <properties>
      <java.version>11</java.version>
    </properties>
    

    这个设置在每个(简单的)pom.xml 中只能出现一次,因为它会影响maven-compiler-plugin 设置源和目标。我再次假设您有一个包含 JDK 6 代码的源目录和另一个包含 JDK 11 代码的源目录。您的目标是以兼容的方式将所有 JDK 6 源代码绑定到一个 EAR。同时,您的 JDK 11 源代码最终位于不同的 EAR 中,并且必须类似于 JDK 11 字节码。

    为 JDK 8 目标编译 JDK 11 源代码是完全不同的——仍然与 JDK 6 VM 不兼容。我还假设仅通过编译器将您的 JDK 11 源代码转换为 JDK 6 字节码既不需要也不容易。

    接下来,我假设您在两个 EAR 的类路径中至少有一个共享元素。它可以是您自己的 API JAR 或外部库。这种依赖最终会出现在所谓的父 pom 的dependencyManagement 中。这是包含所有模块定义的同一个 pom。

    第三,您需要定义一个 groupId 和各种 artifactId。我强烈建议您至少在 artifactId 中表达 JDK 亲和力。然后,您可以根据 JDK 亲和性来表达依赖关系。骨架(父)pom.xml 可能如下所示:

    <project>
      <groupId>com.stackoverflow</groupId>
      <artifactId>sample-cross-release</artifactId>
      <version>1.0.0-SNAPSHOT</version>
    
      <modules>
        <module>sample-cross-release-api</module>
        <module>sample-cross-release-source6</module>
        <module>sample-cross-release-source11</module>
        <module>sample-cross-release-war6</module>
        <module>sample-cross-release-war11</module>
        <module>sample-cross-release-ear6</module>
        <module>sample-cross-release-ear11</module>
      </modules>
    
      <dependencyManagement>
        <dependencies>
          <dependency><!-- necessary for 6 and 11 source/ WAR/ EAR -->
            <groupId>com.stackoverflow</groupId>
            <artifactId>sample-cross-release-api</artifactId>
            <version>${project.version}</version>
          <dependency>
          <dependency><!-- only 6 is shown, 11 looks the similar -->
            <groupId>com.stackoverflow</groupId>
            <artifactId>sample-cross-release-sources6</artifactId>
            <version>${project.version}</version>
          <dependency>
          <dependency><!-- only 6 is shown, 11 looks the similar -->
            <groupId>com.stackoverflow</groupId>
            <artifactId>sample-cross-release-war6</artifactId>
            <version>${project.version}</version>
          <dependency>
        </dependencies>
      </dependencyManagement>
    </project>
    

    我省略了源代码和 WAR 部分。但它在sample-cross-release-sources6 上有一个dependency 和-api。 EAR 的 pom.xml 看起来像这样:

    <project>
      <groupId>com.stackoverflow</groupId>
      <artifactId>sample-cross-release-ear11</artifactId>
      <version>1.0.0-SNAPSHOT</version>
    
      <parent>
        <groupId>com.stackoverflow</groupId>
        <artifactId>sample-cross-release</artifactId>
        <version>1.0.0-SNAPSHOT</version>
      </parent>
    
      <properties>
        <java.version>11</java.version>
      </properties>
    
      <dependencies>
    
        <dependency><!-- does not need version, determined by parent -->
          <groupId>com.stackoverflow</groupId>
          <artifactId>sample-cross-release-api</artifactId>
        <dependency>
    
        <dependency><!-- does not need version, determined by parent -->
          <groupId>com.stackoverflow</groupId>
          <artifactId>sample-cross-release-war6</artifactId>
        <dependency>
    
        <!-- other dependencies, like logging, persistence... -->
      </dependencies>
    
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${maven-compile.version}</version>
            <configuration>
                <source>${java.version}</source>
                <target>${java.version}</target>
            </configuration>
          </plugin>
    
        </plugins>
      </build>
    </project>
    

    项目结构在文件系统中将如下所示:

    |
    +-- pom.xml (parent)
    +-- sample-cross-release-api
    |    +-- pom.xml
    |    +-- src/main/java
    |    +-- src/main/resources
    |    ...
    ...
    +-- sample-cross-release-ear11
         +-- pom.xml
         ...
    

    最后,我敦促您拥有完全独立的 JDK 6 和 JDK 11 代码库/projects/pom.xml-s。不要将它们与父 pom 合并。一旦您尝试设置(Maven-)配置文件以支持不同 JDK/工具链的发布插件,您最终将陷入依赖地狱。它可能适用于简单的情况。一旦你引入静态代码分析、万无一失/故障安全以及大概是 WAR 和 EAR 创建,它就会崩溃。 (我假设 JDK 6 EAR 是使用与 JDK 11 的 JEE 不同的匹配 JEE 依赖项构建的。这反过来又强制使用兼容的 Maven 插件——每个 JDK 都不同。)

    而且您永远不会知道:在 JDK 11 上运行的应用程序服务器会禁止第三方库中的反射访问,该第三方库以某种方式最终出现在您 11 的 EAR 类路径中。从一开始就谨慎行事,将不同的 JDK 拆开并仔细检查两次。

    为了简洁,我省略了:

    • 传递依赖/写 pom 的好风格
    • maven-enforcer-plugin 拥有可重复的构建
    • WAR- 和 EAR-Maven-plugins 的使用,因为它们在 JDK-6 和 -11 版本之间在如何设置类路径方面存在显着差异
    • 使用toolchains,所以所有开发者都有一个共同的平台,可以传播到构建节点
    • 关于 jdeps 的建议,部分原因是 Maven 插件,部分原因是对多版本 jAR 的处理(这将与 JDK 11 依赖项一起显示)
    • 允许命令行开关改变构建行为的 Maven 配置文件
    • 通过 Maven 发布,引入基于 JDK、Maven 和您的 SCM 的有趣怪癖。
    • 静态代码分析,PMD 是在此设置中运行的最灵活之一,即使两个 JDK 具有相同的规则集,而其他 JDK 可能没有或至少不容易(Coverity、Sonarqube、CAST 等)
    • 安全检查,org.owasp:dependency-check-maven 会在 JDK 6 分支中触发很多警告,一些库不再针对这个目标 JDK 发展

    通常一个父 pom 包含很多 dependencyManagementpluginManagement 所以所有模块 pom 可以省略版本和详细配置。您的方法与此相反,强制 JDK 6 分支和 JDK 11 分支通过同一个父级。它总是从父级强制到模块上,后者不能改变或挑选。

    如果从 Ant 切换到 Maven 没有真正的权衡,请不要这样做。 Maven 需要很多合同,尤其是。当涉及到文件系统布局与工件内容时——要构建 WAR/EAR,您要么需要遵守规则,要么需要大量的插件配置。

    【讨论】:

      猜你喜欢
      • 2017-07-06
      • 1970-01-01
      • 2016-04-08
      • 2017-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多