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

时间:2012-11-29 06:46:37

标签: java maven jar maven-shade-plugin

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

我查看了Maven docs,但我无法理解这句话:

  

“这个插件提供了将工件打包在超级jar中的功能,包括它的依赖关系和阴影 - 即重命名 - 一些依赖项的包。”页面上的文档似乎不是新手友好的。

什么是“超级罐子”?为什么有人想制作一个?重命名依赖项包的重点是什么?我试图通过maven-shade-plugin apache页面上的示例,例如“为Uber Jar选择内容”,但我仍然无法理解“着色”所取得的成就。

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

4 个答案:

答案 0 :(得分:295)

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

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

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

只是旁注。避免使用uber-jar作为Maven依赖,因为它破坏了Maven的依赖性解析功能。通常我们只为实际部署或手动分发的最终工件创建uber-jar,但不是为了放入Maven存储库。


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

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

例如,我正在开发Foo库,它依赖于Bar库的特定版本(例如1.0)。假设我无法使用其他版本的Bar lib(因为API更改或其他技术问题等)。如果我只是在Maven中声明Bar:1.0Foo的依赖关系,则可能会遇到问题:Qux项目取决于Foo,还有{{{ 1}}(并且它无法使用Bar:2.0,因为Bar:1.0需要使用Qux中的新功能。这是两难的问题:应Bar:2.0使用QuxBar:1.0的代码无效)或QuxBar:2.0的代码不起作用)?

为了解决这个问题,Foo的开发人员可以选择使用shade插件重命名其Foo的用法,以便Bar jar中的所有类都嵌入Bar:1.0 1}} jar,嵌入式Foo类的包已从Bar更改为com.bar。通过这样做,com.foo.bar可以安全地依赖于Qux,因为现在Bar:2.0不再依赖于Foo,并且它正在使用自己的“已更改”{{1}副本位于另一个包中。

答案 1 :(得分:58)

我最近想知道为什么elasticsearch会对一些(但不是全部)依赖项进行着色并重新定位。以下是项目维护者的解释, @kimchy

  

着色部分是故意的,我们在elasticsearch中使用的着色库是针对elasticsearch的所有意图和目的的部分,所使用的版本与elasticsearch公开的内容以及它如何使用库基于库的内部结构密切相关工作(以及版本之间的变化),netty和番石榴都是很好的例子。

     是的,我实际上提供了几个弹性研究罐子没有问题,一个是没有阴影的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>

答案 2 :(得分:3)

我认为需要“阴影” jar的一个示例是AWS Lambda函数。它们似乎只允许您上传1个jar,而不像典型的.war文件中那样包含整个.jars集合。因此,创建一个具有所有项目依赖项的.jar可以使您做到这一点。

答案 3 :(得分:2)

小警告

虽然没有说明为什么人们想要使用maven-shade-plugin(因为所选答案很好地描述了它),但我想指出我遇到了问题。它改变了JAR(因为它正在做什么)并且它在我的软件中引起了回归。

所以,我没有使用它(或maven-jarjar-plugin),而是使用了JarJar的二进制文件,它似乎没有问题。

我在这里发布了我的解决方案,因为我花了一些时间才找到合适的解决方案。

Downlaod JarJar的JAR文件

你可以从这里下载jar: https://code.google.com/p/jarjar/ 在左侧菜单中,您有一个下载链接。

如何使用JarJar将JAR的类从一个包重定位到另一个包

在这个例子中,我们将从&#34; com.fasterxml.jackson&#34;更改包。 to&#34; io.kuku.dependencies.com.fasterxml.jackson"。 - 源JAR被称为&#34; jackson-databind-2.6.4.jar&#34;新的修改(目标)JAR被称为&#34; kuku-jackson-databind-2.6.4.jar&#34;。 - &#34; jarjar&#34; JAR文件版本为1.4

  1. 创建&#34; rules.txt&#34;文件。该文件的内容应该是(观察&#39; @&#39;字符之前的时间段): 规则com.fasterxml.jackson。** io.kuku.dependencies.com.fasterxml.jackson。@ 1

  2. 运行以下命令: java -jar jarjar-1.4.jar process rules.txt jackson-databind-2.6.4.jar kuku-jackson-databind-2.6.4.jar

  3. 将修改后的JAR安装到本地存储库

    在这种情况下,我要安装位于&#34; c:\ my-jars \&#34;上的3个文件。文件夹中。

    mvn install:install-file -Dfile = C:\ my-jars \ kuku-jackson-annotations-2.6.4.jar -DgroupId = io.kuku.dependencies -DartifactId = kuku-jackson-annotations -Dversion = 2.6 .4 -Dpackaging = jar

    mvn install:install-file -Dfile = C:\ my-jars \ kuku-jackson-core-2.6.4.jar -DgroupId = io.kuku.dependencies -DartifactId = kuku-jackson-core -Dversion = 2.6 .4 -Dpackaging = jar

    mvn install:install-file -Dfile = C:\ my-jars \ kuku-jackson-databind-2.6.4.jar -DgroupId = io.kuku.dependencies -DartifactId = kuku-jackson-annotations -Dversion = 2.6 .4 -Dpackaging = jar

    在项目的pom

    中使用修改后的JAR

    在这个例子中,这是&#34;依赖&#34;项目中的元素:

    <dependencies>
        <!-- ================================================== -->
        <!-- kuku JARs -->
        <!-- ================================================== -->
        <dependency>
            <groupId>io.kuku.dependencies</groupId>
            <artifactId>kuku-jackson-annotations</artifactId>
            <version>2.6.4</version>
        </dependency>
        <dependency>
            <groupId>io.kuku.dependencies</groupId>
            <artifactId>kuku-jackson-core</artifactId>
            <version>2.6.4</version>
        </dependency>
        <dependency>
            <groupId>io.kuku.dependencies</groupId>
            <artifactId>kuku-jackson-databind</artifactId>
            <version>2.6.4</version>
        </dependency>
    </dependencies>