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

non*_*ing 262 java jar maven maven-shade-plugin

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

我查看了Maven文档,但是我无法理解这句话:

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

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

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

Adr*_*hum 313

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

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

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

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


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

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

例如,我正在开发Foo库,它依赖于库的特定版本(例如1.0)Bar.假设我无法使用其他版本的Barlib(因为API更改或其他技术问题等).如果我只是在Maven中声明Bar:1.0Foo依赖,则可能会遇到问题:Qux项目依赖于Foo,并且Bar:2.0(Bar:1.0因为Qux需要使用新功能而无法使用Bar:2.0).这就是困境:应该Qux使用Bar:1.0(哪些Qux代码不起作用)或Bar:2.0(哪些Foo代码不起作用)?

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

  • 我不确定名称背后的原因,但从头版来看,似乎暗示"阴影"描述了依赖关系的"隐藏".由于您可以选择在着色JAR中包含一些依赖项,因此shade插件也会为您生成正确的POM,从而删除包含的依赖项.阴影似乎描述了这个过程 (6认同)
  • 谢谢,这有很大帮助.它被称为"阴影",因为它隐藏了超级罐内的依赖关系和其他罐子吗? (5认同)
  • 只是一个小问题:它会阻止 `Class.forName` 工作吗? (4认同)
  • @SurajMenon:使用Shade插件是创建超级jar的最简单方法.但是,您也可以使用Assembly插件,并使用内置的`jar-with-dependency`描述符.对于使用uber-jar的依赖性洗脱问题,我已经在我的回答中提到:不要使用uber-jar作为依赖,期间.更详细一点:在创建超级jar之前,你应该拥有一个具有正常依赖性的普通项目.原始神器是你应该用作依赖的(而不是超级jar) (3认同)

Tom*_*Tom 58

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

着色部分是有意的,我们在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构建文件,文本文件等,它们与某些依赖项打包在一起,但不属于uber 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>
Run Code Online (Sandbox Code Playgroud)


ato*_*m88 8

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