如何在 maven-war-plugin 中正确设置清单类路径

Posted

技术标签:

【中文标题】如何在 maven-war-plugin 中正确设置清单类路径【英文标题】:How to set up manifest class-path properly in maven-war-plugin 【发布时间】:2012-03-03 11:53:01 【问题描述】:

我已将 maven-ear-plugin 与 maven-war-plugin 和 maven-ejb-plugin 一起使用,成功部署并运行打包为 EAR 到 Jboss AS7 的应用程序。

.
|-- META-INF
|   |-- application.xml
|   |-- MANIFEST.MF
|   `-- maven
|       `-- com.patrac
|           `-- Patrac-ear
|               |-- pom.properties
|               `-- pom.xml
|-- Patrac-ejb-1.0-SNAPSHOT.jar
`-- Patrac-web-1.0-SNAPSHOT.war

在应用程序源代码目录中,pom的位置如下:

.
|
|-- Patrac-ear
|   `-- pom.xml
|-- Patrac-ejb
|  `-- pom.xml
|-- Patrac-web
|   `-- pom.xml
`-- pom.xml

我不知道如何在部署应用程序时停止一些烦人的警告消息:

12:32:03,958 WARN  [org.jboss.as.server.deployment] (MSC service thread 1-2) Class Path entry richfaces-components-ui-4.0.0.Final.jar in "/content/Patrac.ear/Patrac-web-1.0-SNAPSHOT.war"  does not point to a valid jar for a Class-Path reference.
12:32:03,970 WARN  [org.jboss.as.server.deployment] (MSC service thread 1-2) Class Path entry richfaces-components-api-4.0.0.Final.jar in "/content/Patrac.ear/Patrac-web-1.0-SNAPSHOT.war"  does not point to a valid jar for a Class-Path reference.
12:32:03,984 WARN  [org.jboss.as.server.deployment] (MSC service thread 1-2) Class Path entry richfaces-core-api-4.0.0.Final.jar in "/content/Patrac.ear/Patrac-web-1.0-SNAPSHOT.war"  does not point to a valid jar for a Class-Path reference.
12:32:03,989 WARN  [org.jboss.as.server.deployment] (MSC service thread 1-2) Class Path entry richfaces-core-impl-4.0.0.Final.jar in "/content/Patrac.ear/Patrac-web-1.0-SNAPSHOT.war"  does not point to a valid jar for a Class-Path reference.

Patrac-web-1.0-SNAPSHOT.war!META-INF/MANIFEST.MF 如下所示:

Manifest-Version: 1.0
Built-By: pgarner
Build-Jdk: 1.7.0_02
Class-Path: Patrac-ejb-1.0-SNAPSHOT.jar richfaces-components-ui-4.0.0.
 Final.jar richfaces-components-api-4.0.0.Final.jar richfaces-core-api
 -4.0.0.Final.jar richfaces-core-impl-4.0.0.Final.jar cssparser-0.9.5.
 jar sac-1.3.jar guava-r08.jar
Created-By: Apache Maven
Archiver-Version: Plexus Archiver

为了可移植性,EJB 模块需要存在 ejb 类路径条目,并且 Richfaces、cssparser 和 guava 类路径条目不应出现在 WAR 的清单中。

问题是我的 WAR 依赖于所有 JAR,其中一些位于 WEB-INF/lib (RichFaces) 中,还有一个 JAR Patrac-ejb-1.0-SNAPSHOT.jar 位于 EAR 的根目录中。每个依赖项都需要在 Patrac-web/pom.xml 中输入,但不是每个依赖项都应该出现在清单中。

Maven 将 JAR 放在正确的位置,但它会将所有 JAR 的 Class-Path 条目放入清单中。它不应该这样做。它应该只为Patrac-ejb-1.0-SNAPSHOT.jar 输入一个条目。

  <!--
    According to Java EE 6 spec, the application is portable if
    Patrac-web.war's META-INF/MANIFEST.MF contains a Class-Path entry
    for Patrac-ejb-1.0-SNAPSHOT.jar.

    <optional>true</optional> is the flag that maven-war-plugin uses
    to put the entry in MANIFEST.MF without copying Patrac-ejb-1.0-SNAPSHOT.jar
    into WEB-INF/lib.  This is what I want.

    <scope>provided</scope> would cause maven-war-plugin to NEITHER
    put the entry in MANIFEST.MF nor copy Patrac-ejb.jar into WEB-INF/lib,
    which would not be good.

    No tag at all would cause maven-war-plugin to BOTH put the entry in
    MANIFEST.MF and copy Patrac-ejb.jar into WEB-INF/lib, which would
    also not be good.
  -->
  <dependency>
     <groupId>com.patrac</groupId>
     <artifactId>Patrac-ejb</artifactId>
     <type>ejb</type>
     <optional>true</optional>
  </dependency>

  <!--
   These two dependencies are used to copy
  the other JAR files into WEB-INF/lib and there
  should not be any class-path entries for such
  JARs in MANIFEST.MF, in order to avoid the
  error messages.
  -->
    <dependency>
        <groupId>org.richfaces.ui</groupId>
        <artifactId>richfaces-components-ui</artifactId>
    </dependency>
    <dependency>
        <groupId>org.richfaces.core</groupId>
        <artifactId>richfaces-core-impl</artifactId>
    </dependency>

我正在使用最新的 maven-war-plugin 版本 2.2。如何告诉 maven-war-plugin 将“非 ejb”JAR 放入 WEB-INF/lib 中而不将类路径条目放入 MANIFEST.MF?

非常感谢您的任何建议或指示。

参考资料:

Maven War Plugin Maven Ear Plugin

【问题讨论】:

【参考方案1】:

专门阅读关于瘦身战争的文章

http://maven.apache.org/plugins/maven-war-plugin/examples/skinny-wars.html

【讨论】:

【参考方案2】:

EJB 模块需要存在 ejb 类路径条目……

类路径只需要存在于引用其他 EJB 模块(在同一 EAR 的根目录中)的 EJB 模块(在 EAR 的根目录中)

【讨论】:

【参考方案3】:

Maven WAR plugin 使用的Maven archiver 提供了一种在 WAR 清单中生成 Class-Path 条目的方法,但不幸的是存档器采用了全有或全无的方法。将addClassPath=true 传递给存档配置后,存档器会将 所有 WAR 必需和可选依赖项的 Class-Path 条目放入清单中。

但是,有些条目根本不属于那里。 Class-Path 条目用于表示"Download Extensions," 或对WAR 的外部 JAR 的引用。位于WEB-INF/lib 的JAR 不应该,因此在WAR 的清单中有Class-Path 条目。当您在存档器中设置addClassPath=true 时,Maven 的 War 插件会打破此规则。

此外,当您将addClassPath=true 传递给 Maven 的归档程序时,它会为所有 Class-Path 条目提供相同的目录前缀——无论依赖项位于 EAR 中的什么位置。当可选依赖项和必需依赖项位于不同的位置(例如 EAR 根目录、EAR lib 和 WAR WEB-INF/lib)时,这会导致问题。

自然地,当部署一个 EAR 其 WAR 清单包含上述错误时,如果 WAR 类加载器最终可以找到依赖项(位于 WEB-INF/lib 中的 JAR),JBoss 会抛出警告,如果类路径前缀错误(例如 on EAR lib 目录中的 EJB JAR 或依赖项)。

因此,如果您的 WAR 和我的一样,依赖于位于 EAR 根目录的 EJB 模块,以及位于WEB-INF/lib 中的任意数量的依赖项,Maven 归档器将为所有无论它们在 EAR 中的位置如何,它们都将具有相同的前缀。

不好。

如果归档器提供一种方法来排除位于 WEB-INF 中的 JAR 的 Class-Path 条目,这个问题将会有所改善。但事实并非如此。

以下是使用addClassPath=true 时每个依赖项设置的结果摘要:

           Setting                  Generate               Copy JAR into
                                   Class-Path              WEB-INF/lib
                                     Entry

1.  <scope>provided</scope>             NO                      NO

2.  <optional>true</optional>          YES                      NO

3.  (no option -- default)             YES                     YES

4.  ?????                               NO                     YES

需要覆盖上述情况 #4:不要创建 Class-Path 条目,是的,将 JAR 复制到 WEB-INF/lib。 Maven 归档器应该默认实现这个行为。

我能想到的最佳解决方案是使用蛮力并关闭 Maven 存档器的自动 Class-Path 条目生成。相反,我使用归档器的manifestEntries 选项在WAR 清单中为EJB 模块显式创建一个Class-Path 条目。这样做的方法是从Patrac-web/pom.xml 中删除以下内容:

<manifest>
    <addClasspath>true</addClasspath>
</manifest>

并将其替换为:

<manifestEntries>
    <Class-Path>Patrac-ejb-$project.version.jar</Class-Path>
</manifestEntries>

使用此配置,只为 EJB 模块显式创建一个 Class-Path 条目。

【讨论】:

【参考方案4】:

对于那些需要从MANIFESTWEB-INF/lib 中排除的JAR,您需要将它们标记为&lt;scope&gt;provided&lt;/scope&gt;。这意味着 JAR 文件将由容器提供(在您的情况下是 EAR)。

其他选项请查看WAR manifest guide。

【讨论】:

War manifest guide 显示了 3 个示例并提供了注释:“没有显示如何在 WEB-INF/lib 但不在清单类路径中包含依赖项。”指南然后说:“查看Guide to Working with Manifests 以获取更多示例。”第二页只是让我回到 WAR 清单指南页面。我需要能够遵循未显示的示例。 您想在 WEB-INF/lib 中包含依赖项,但不在清单类路径中?为什么你需要那个?如果您的richfacescssparserguava 留在EAR 中,那么这些依赖项应标记​​为provided Richfaces 等是 WAR 模块的必需依赖项。因此,它们应该在 WEB-INF/lib 中。我的理解是,不需要为 WEB-INF 中的 JAR 创建 Class-Path 条目,因为此类文件由 WAR 的类加载器自动加载。只有 WAR 模块 external 的 JAR 的 Class-Path 条目需要输入到 WAR 的清单中。在我的例子中,必须为 EJB JAR 创建一个条目。这是每个 JEE 规范。 RichFaces 等是 WAR 模块的必需依赖项,因此不应标记为 provided 所以,一切正常。只是 RichFaces 依赖项不应在 WAR 清单中包含 Class-Path 条目。当存在 Class-Path 条目时,部署期间会出现 WARNING 消息。 JBoss 抱怨它无法在全局 EAR 目录中找到 RichFaces 依赖项,因为它从 maven-war-plugin 放在那里的清单中读取 Class-Path 条目。但是,应用程序运行良好,因为 JBoss 自动在 WEB-INF/lib 中找到 RichFaces JAR。 WEB-INF/lib 中的 JAR 不应在清单中包含 Class-Path 条目。 EAR 不是 JEE 容器,即使从类加载器的角度来看也是如此!如果您想了解 JEE 中类加载的工作原理,请阅读 JEE 规范。 tools.jar 与此讨论无关! RichFaces 永远不应该进入服务器/库,甚至不应该试图说明问题!讨论完毕。你的帖子很荒谬,没有帮助。请停下来。

以上是关于如何在 maven-war-plugin 中正确设置清单类路径的主要内容,如果未能解决你的问题,请参考以下文章

为啥 maven-war-plugin 不打包我的文件?

maven-war-plugin

通过maven-war-plugin插件对war包分环境打包

用户登录如何设计测试用例?

执行 org.apache.maven.plugins:maven-war-plugin:2.1.1:war 时缺少必需的类

Eclipse导入Maven项目出现:Could not calculate build plan: Plugin org.apache.maven.plugins:maven-war-plugin: