maven-shade-plugin 的用途是什么,为什么要重新定位 Java 包?

新手上路,请多包涵

我发现有人在 pom.xml 中使用了 maven-shade-plugin。我以前从未使用过 maven-shade-plugin(我是 Maven n00b),所以我试图了解使用它的原因以及它的作用。

我查看了 Maven 文档,但是我无法理解这个声明:

这个插件提供了将工件打包在 uber-jar 中的能力,包括它的依赖项和遮蔽 - 即重命名 - 一些依赖项的包。

页面上的文档似乎对新手不太友好。

什么是“超级罐”?为什么有人想做一个?重命名依赖项的包有什么意义?我尝试浏览 maven-shade-plugin apache 页面上的示例,例如“为 Uber Jar 选择内容”,但我仍然无法理解“着色”正在完成什么。

任何指向说明性示例/用例的指针(解释为什么在这种情况下需要阴影 - 它解决了什么问题)将不胜感激。最后,我应该什么时候使用 maven-shade-plugin?

原文由 nonbeing 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.4k
2 个回答

简而言之,Uber JAR 是一个包含所有内容的 JAR。

通常在 Maven 中,我们依赖于依赖管理。工件仅包含其自身的类/资源。 Maven 将负责根据项目的构建时间找出项目的所有工件(JAR 等)。

uber-jar 是一种获取所有依赖项的东西,并提取依赖项的内容并将它们与项目本身的类/资源一起放在一个大 JAR 中。通过拥有这样一个 uber-jar,执行起来很容易,因为您只需要一个大 JAR 而不是大量的小 JAR 来运行您的应用程序。在某些情况下,它还简化了分发。

附带说明:避免使用 uber-jar 作为 Maven 依赖项,因为它会破坏 Maven 的依赖项解析功能。通常我们只为实际部署或手动分发的最终工件创建一个 uber-jar,而不是用于放入 Maven 存储库。


更新:我刚刚发现我还没有回答问题的一部分:“重命名依赖项的包有什么意义?”。以下是一些简短的更新,希望能帮助有类似问题的人。

创建一个易于部署的 uber-jar 是 shade 插件的一个用例。还有其他涉及包重命名的常见用例。

例如,我正在开发 Foo 库,它依赖于 Bar 库的特定版本(例如 1.0)。假设我不能使用 Bar lib 的其他版本(因为 API 更改或其他技术问题等)。 If I simply declare Bar:1.0 as Foo ’s dependency in Maven, it is possible to fall into a problem: A Qux project is depending on Foo , and also Bar:2.0 (and it cannot use Bar:1.0 because Qux needs to use new feature in Bar:2.0 ). Here is the dilemma: should Qux use Bar:1.0 (which Qux ’s code will not work) or Bar:2.0 (which Foo 的代码不起作用)?

为了解决这个问题, Foo 的开发者可以选择使用shade插件重命名 Bar 的用法,这样 Bar:1.0 jar在 Foo jar 中,嵌入的 Bar classes 的包从 com.bar 更改为 com.foo.bar 。 By doing so, Qux can safely depends on Bar:2.0 because now Foo is no longer depending on Bar , and it is using its own “更改”的副本 Bar 位于另一个包中。

在此处输入图像描述

原文由 Adrian Shum 发布,翻译遵循 CC BY-SA 4.0 许可协议

我最近想知道为什么 elasticsearch 会隐藏和重新定位它的一些(但不是全部)依赖项。这是项目维护者 @kimchy 的解释:

阴影部分是有意的,我们在 elasticsearch 中使用的阴影库是 elasticsearch 的所有意图和目的的一部分,所使用的版本与 elasticsearch 公开的内容以及它如何根据库工作的内部结构(以及版本之间的变化),netty 和 guava 就是很好的例子。

顺便说一句,我实际上提供了几罐 elasticsearch 没有问题,一罐没有着色的 lucene,一罐有着色的 Lucene。虽然不确定如何使用 Maven 来完成。例如,我不想提供一个不遮蔽 netty/jackson 的版本,因为 elasticsearch 对它们有很深的亲密使用(例如,将即将到来的缓冲改进与任何以前版本的 netty 一起使用,除了当前版本将与使用更少的内存相比,实际上使用更多的内存)。

-- https://github.com/elasticsearch/elasticsearch/issues/2091#issuecomment-7156766

另一个来自 drewr

阴影对于使我们的依赖项(尤其是 netty、lucene、guava)靠近我们的代码很重要,这样即使上游提供者落后,我们也可以解决问题。我们可能会分发代码的模块化版本,这将有助于解决您的特定问题(例如#2091),但此时我们不能简单地删除阴影依赖项。在没有更好的解决方案之前,您可以根据自己的目的构建本地版本的 ES。

-- https://github.com/elasticsearch/elasticsearch/pull/3244#issuecomment-20125452

所以,这是一个用例。至于说明性示例,下面是如何在 elasticsearch 的 pom.xml (v0.90.5) 中使用 maven-shade-plugin。 artifactSet::include 行指示它将哪些依赖项拉入 uber JAR(基本上,当生成目标 elasticsearch jar 时,它们被解压缩并与 elasticsearch 自己的类一起重新打包。(以防您不知道这已经是一个 JAR 文件只是一个 ZIP 文件,其中包含程序的类、资源等,以及一些元数据。您可以提取一个以查看它是如何组合在一起的。)

relocations::relocation 行是相似的,除了在每种情况下它们还将指定的替换应用于依赖项的类 - 在这种情况下,将它们置于 org.elasticsearch.common 下。

最后, filters 部分从目标 JAR 中排除了一些不应该存在的内容——例如 JAR 元数据、ant 构建文件、文本文件等,它们与一些依赖项打包在一起,但它们不存在它属于超级 JAR。

 <plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>2.1</version>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>shade</goal>
                </goals>
            </execution>
        </executions>
        <configuration>
            <minimizeJar>true</minimizeJar>
            <artifactSet>
                <includes>
                    <include>com.google.guava:guava</include>
                    <include>net.sf.trove4j:trove4j</include>
                    <include>org.mvel:mvel2</include>
                    <include>com.fasterxml.jackson.core:jackson-core</include>
                    <include>com.fasterxml.jackson.dataformat:jackson-dataformat-smile</include>
                    <include>com.fasterxml.jackson.dataformat:jackson-dataformat-yaml</include>
                    <include>joda-time:joda-time</include>
                    <include>io.netty:netty</include>
                    <include>com.ning:compress-lzf</include>
                </includes>
            </artifactSet>
            <relocations>
                <relocation>
                    <pattern>com.google.common</pattern>
                    <shadedPattern>org.elasticsearch.common</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>gnu.trove</pattern>
                    <shadedPattern>org.elasticsearch.common.trove</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>jsr166y</pattern>
                    <shadedPattern>org.elasticsearch.common.util.concurrent.jsr166y</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>jsr166e</pattern>
                    <shadedPattern>org.elasticsearch.common.util.concurrent.jsr166e</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>org.mvel2</pattern>
                    <shadedPattern>org.elasticsearch.common.mvel2</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>com.fasterxml.jackson</pattern>
                    <shadedPattern>org.elasticsearch.common.jackson</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>org.joda</pattern>
                    <shadedPattern>org.elasticsearch.common.joda</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>org.jboss.netty</pattern>
                    <shadedPattern>org.elasticsearch.common.netty</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>com.ning.compress</pattern>
                    <shadedPattern>org.elasticsearch.common.compress</shadedPattern>
                </relocation>
            </relocations>
            <filters>
                <filter>
                    <artifact>*:*</artifact>
                    <excludes>
                        <exclude>META-INF/license/**</exclude>
                        <exclude>META-INF/*</exclude>
                        <exclude>META-INF/maven/**</exclude>
                        <exclude>LICENSE</exclude>
                        <exclude>NOTICE</exclude>
                        <exclude>/*.txt</exclude>
                        <exclude>build.properties</exclude>
                    </excludes>
                </filter>
            </filters>
        </configuration>
    </plugin>
</plugins>

原文由 Tom 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题