Maven阴影jar用作外部项目依赖

时间:2016-09-02 07:25:48

标签: maven maven-3 maven-shade-plugin uberjar

我在项目中使用了maven shade插件来重定位一个包下的所有依赖jar类,例如org.shade。*

当我尝试在其他应用程序中使用该阴影jar作为maven依赖时,它会拉动依赖jar。

我的期望是当uber / shaded jar包含为maven依赖时,它不应该拉任何其他依赖类jar,因为已经在shaded jar中重新打包这些类。

2 个答案:

答案 0 :(得分:2)


在生成uber jar的 源项目 上的pom.xml声明了传递性依赖项(如果将其作为依赖项包含在 external中)项目 ,那么Maven将尝试获取这些文件(即使这些文件已包含在uber jar中)。

我共享一个解决方案,让您避免像@A_DiMatteo在其解决方案中所解释的那样,将所有传递性依赖项(包括它)明确排除在外部项目中(我也同意他避免使用uber jar作为依赖项(如果出于某种原因并非绝对必要))。因此,您应该能够在不使用 exclusions 元素的情况下包括uber jar依赖项,如下所示:

<dependency>
  <groupId>com.sample</groupId>
  <artifactId>something-uber</artifactId>
  <version>some-version</version>
</dependency>
  

前提:我的目标是在存储库中同时提供 uber (没有在pom上声明传递依赖项)和 thin 罐子。因此,我的解决方案“ A”是基于这种情况的,目前存在限制,即将有阴影的jar上载到存储库2次。

     
      
  • 仅提供 uber jar,请参见下面的“ B”解决方案
  •   
  • 有关“ A”限制的可能解决方案,请参阅最后的更新部分
  •   

A)在存储库中同时提供瘦罐和超罐子

1-在您的 源项目 上,在事物模块pom.xml上配置以下 maven-shade-plugin 如下:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <version>2.2</version>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <finalName>something-uber-${project.version}</finalName>
      </configuration>
    </execution>
  </executions>
</plugin>

然后使用 build-helper-maven-plugin 插件将新工件与模块上的“超级”分类器相连:

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>build-helper-maven-plugin</artifactId>
  <version>1.2</version>
  <executions>
    <execution>
      <id>attach-artifacts</id>
      <phase>package</phase>
      <goals>
        <goal>attach-artifact</goal>
      </goals>
      <configuration>
        <artifacts>
          <artifact>
            <file>
              ${project.build.directory}/something-uber-${project.version}.jar
            </file>
            <classifier>uber</classifier>
          </artifact>
        </artifacts>
      </configuration>
    </execution>
  </executions>
</plugin>

这将作为Maven安装阶段的结果,在 target / 目录上生成以下两个jar:

40K something-0.1.0.jar
7M  something-uber-0.1.0.jar
  

警告::然后执行maven部署阶段两个jar都将上传到存储库中!!此处的目标应该是仅上传 thin jar >跳过部署有阴影的jar 以便将其保留为本地工件(有关可能的修复,请参见最后的 UPDATE 部分)

2-然后在您的源项目上创建另一个名为 something-uber 的模块,并添加以下依赖项和插件:

<dependencies>
    <dependency>
        <groupId>com.sample</groupId>
        <artifactId>something</artifactId>
        <version>${project.version}</version>
        <classifier>uber</classifier>
        <exclusions>
            <exclusion>
                <artifactId>*</artifactId>
                <groupId>*</groupId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>2.2</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

请注意以下有关包括依赖项的信息:​​

  • 分类器应等于 uber (您在第一个模块上使用 build-helper-maven-plugin 指定附加新工件的分类器)
  • 已指定排除项

在该模块上的maven部署阶段结束时,已着色的jar将上传到存储库中,您可以将其作为依赖项添加到外部项目中,如下所示:

<dependency>
 <groupId>com.sample</groupId>
 <artifactId>something-uber</artifactId>
 <version>0.1.0</version>
</dependency>

B)在存储库中仅提供uber jar

从解决方案“ A”开始,如果要避免在存储库中提供 thin jar ,则应避免在第1点上在maven-shade-plugin上指定 finalName 配置,因此也请避免使用 build-helper-maven-plugin 插件,因为没有要附加的新工件。 这样做,在模块上部署目标/上只有uber jar作为默认模块(不带分类器):

7M  something-0.1.0.jar

您还应该跳过上传操作,否则在这里还将上传两个胖子( something-0.1.0.jar something-uber-0.1.0.jar )。 为此,在同一模块上添加以下插件:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-deploy-plugin</artifactId>
    <version>2.8.2</version>
    <configuration>
        <skip>true</skip>
    </configuration>
</plugin>

在第2点的结尾,只需避免在添加依赖项时指定分类器,如下所示:

<dependencies>
 <dependency>
    <groupId>com.sample</groupId>
    <artifactId>something</artifactId>
    <version>${project.version}</version>
    <exclusions>
        <exclusion>
            <artifactId>*</artifactId>
            <groupId>*</groupId>
        </exclusion>
    </exclusions>
 </dependency>
</dependencies>

更新:跳过A)解决方案上的第一个有阴影的jar上传

在寻找解决方案一段时间后,我决定从GitHub派发 maven-deploy-plugin 插件并尝试一项新功能,以跳过添加第一个模块时创建的有阴影的jar插件配置如下:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-deploy-plugin</artifactId>
  <version>3.0.0-SNAPSHOT</version>
  <configuration>
    <skipAttachedArtifacts>
      <artifact>
        <groupId>com.sample</groupId>
        <artifactId>something</artifactId>
        <version>${project.version}</version>
        <packaging>jar</packaging>
        <classifier>uber</classifier>
      </artifact>
    </skipAttachedArtifacts>
  </configuration>
</plugin>
  

当前使用 maven-deploy-plugin 插件将所有工件从部署中排除,而此处的目标是仅排除特定工件。在我的叉子上,我引入了“ skipAttachedArtifacts”配置参数,以便指定从部署中排除的附加工件。

这是我在GitHub上的分支项目上的链接: https://github.com/gregorycallea/maven-deploy-plugin

这里是我在apache插件项目上提交的拉取请求的链接: https://github.com/apache/maven-deploy-plugin/pull/3

答案 1 :(得分:1)

经典场景是:

  • 生成uber-jar的项目有自己的依赖项(dependency文件中的pom.xml元素),然后将它们打包在一个超级jar中作为Maven工件
  • 当使用这个uber-jar作为另一个项目的依赖项(dependency元素)时,Maven会检查它的<artifact>-<version>.pom文件(与最终工件一起发布到Maven存储库中),这是基本上是其原始pom.xml文件的重命名副本,其中声明了依赖项(dependency元素)(确切地说是打包到uber-jar中的依赖项)。
  • 由于您已将它们打包,因此您可以忽略.pom文件(及其dependencies元素),因为您需要添加exclusions如下:

    <dependency>
        <groupId>com.sample</groupId>
        <artifactId>something-uber</artifactId>
        <version>some-version</version>
        <exclusions>
            <exclusion>
                <groupId>*</groupId>
                <artifactId>*</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    

注意:上述功能仅在Maven 3.2.1之后可用。

因此,您向Maven表明,您不希望任何传递依赖,Maven dependency mediation则不会触发它们。

作为旁注:将uber-jar作为项目的依赖项并不是一个好习惯:它只会使维护变得更难,因为您无法通过dependencyManagement或{来控制传递依赖项{1}}依赖项目的顺序。因此,每当依赖(其中一个传递依赖)需要维护(更改版本等)时,您将始终需要重新打包超级jar,并且对依赖项目的控制更少(再次,更难维护)。 / p>