如何让maven将所有对于war文件通用的jar包放置在同一个EAR根目录下?

26
我们有一个解决方案,其中包含许多战争。这些战争在使用 Hibernate 和 Spring 方面都非常相似。这意味着每个战争中都有许多相同的 jar 包。这已经成为一个问题,因为 ear 的大小开始变得不成比例。
我想使用 Maven 来计算依赖关系,并将所有多个战争共同使用的 jar 包放置在 EAR 的根目录下。
我尝试使用 j2ee 原型(maven-archetype-j2ee-simple)来组织我的项目,但所有战争仍然会在 WEB-INF/lib 中打包依赖项。 是否有一种方法可以使 Maven 计算公共依赖项并将它们放置到 EAR 中,就像构建 war 或 jar 时能够计算所有传递依赖关系一样?
4个回答

69
作为您在评论中提到的,Maven 的任务是计算每个依赖项。当您创建一个构件时,对于每个常见的依赖项,您还需要猜测哪些依赖项属于其中。
还可能出现这样的情况:您必须在另一台没有 ear 的机器上部署一个 war 和其依赖项,如果您将每个 war 依赖项设置为 provided,则会再次陷入困境。
获取精简的 wars 的唯一正确方法是从示例中获取: http://maven.apache.org/plugins/maven-war-plugin/examples/skinny-wars.html 但是,现在来了有趣的部分,有一个大大的快捷方式(完全消除了上述痛苦),可以告诉 Maven 您的 WARs 具有哪些依赖项。
进入 EAR 模块并声明每个 WAR 依赖项的第二个依赖项类型为 pom。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
    <groupId>com.foo</groupId>
    <artifactId>skinny</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>ear</artifactId>
<packaging>ear</packaging>
<dependencies>
    <dependency>
        <groupId>com.foo</groupId>
        <artifactId>war</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <type>war</type>
    </dependency>
    <dependency>
        <groupId>com.foo</groupId>
        <artifactId>war</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <type>pom</type>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-ear-plugin</artifactId>
            <version>2.8</version>
            <configuration>
                <skinnyWars>true</skinnyWars>
                <defaultLibBundleDir>lib</defaultLibBundleDir>
                <modules>
                    <webModule>
                        <groupId>com.foo</groupId>
                        <artifactId>war</artifactId>
                    </webModule>
                </modules>
            </configuration>
        </plugin>
    </plugins>
</build>

现在,每个WAR将独立打包,带有自己的依赖项,并且EAR将与瘦WAR一起打包,所有依赖项都在lib文件夹中。
更新:
请记住,在像JBoss EAP 6这样的严格容器中,ear/lib文件夹不能用于每个依赖项jar。 JSF组件库(如tomahawk、primefaces等)必须驻留在WEB-INF/lib文件夹中。
使用上述描述的解决方案实现这一点的一个方便方法是,在EAR的pom.xml中排除组件库,如下所示:
...
<dependencies>
    <dependency>
        <groupId>com.foo</groupId>
        <artifactId>war</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <type>war</type>
    </dependency>
    <dependency>
        <groupId>com.foo</groupId>
        <artifactId>war</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <type>pom</type>
        <exclusions>
            <exclusion>
                <groupId>org.primefaces</groupId>
                <artifactId>primefaces</artifactId>
            <exclusion>
        </exclusions>
    </dependency>
</dependencies>
...

现在WAR的所有依赖都将放置在ear/lib文件夹中,除了组件库,它将被放置在WAR内的WEB-INF/lib文件夹中。

4
这篇文章真的需要更多的点赞!!太棒了! :D - Andrea Ligios
1
太好了! :) 这真的帮助了我! - Christophe
这个解决方案是否也适用于更深层次的依赖关系?还是我需要明确在WAR中声明这些构件,以便在EAR中排除它们? - Ivo Limmen
1
这是一个非常巧妙的技巧 - 它可以使企业应用程序中依赖项的管理变得更加容易,尤其是在打包进 EAR 中时。它将所有传递性依赖项捆绑到 <ear>/lib 目录中,同时只在根目录捆绑了精简的 WAR 文件。值得称赞! - Matthew Cachia
1
这实际上是有效的,应该是最佳答案。它创建了一些很好的隔离。WAR的pom.xml不必被触及,保持与EAR项目解耦。 - timh
显示剩余2条评论

9
创建一个名为commons-jars的新构件,并将其打包为pom。它应该依赖于您正在使用的所有公共jar - Spring、Hibernate、Log4j等。
然后,在每个war中,将其作为"provided"范围的依赖项添加(并不要忘记将类型设置为pom)。您将能够在类路径中看到它,但它们不会被打包到war中。这样,您还可以将特定于war的依赖项打包到其中,skinny wars的解决方案无法提供此功能。

那么在我们创建了commons-jars.jar之后,应该将其添加到1)server/default/lib还是2)ear根目录下呢? - Rips
2
不是最好的选择,看下一个答案! - Christophe
3
请定义“下一个”答案。提供答案者或链接会更有帮助,因为它们可能会根据投票而交换位置。 - Benjamin Marwell

4

4
现在是痛苦的部分。你的EAR项目的pom.xml文件需要列出WAR项目所依赖的每个库。这是因为Maven假定WAR包含所有依赖,而不会包含EAR中WAR的传递依赖。我想使用Maven来计算依赖项...如果不使用Maven计算依赖项,那么就行不通了... - Dan
2
@Dan,阅读Turbokiwi的答案,了解如何以绝佳的方式避免痛苦的部分 :) - Andrea Ligios

4
你可以将依赖范围设置为“provided”。这意味着它们将由其他模块提供,并不会包含在最终的Jar或War中。
也许assembly插件可以帮助你在打包最终的EAR时将公共JAR放置在那里。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接