9

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

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

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

4

2 回答 2

8

经典场景是:

  • 生成 uber-jar 的项目有自己的依赖项(文件dependency中的元素pom.xml),然后将它们打包在一个 uber-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 依赖调解不会触发它们。


附带说明:将 uber-jar 作为项目的依赖项并不是一个好习惯:它只会使维护变得更加困难,因为您无法通过依赖项目的顺序dependencyManagementdependencies顺序来控制传递依赖项。因此,每当依赖项(其传递的一个)需要维护(更改版本等)并且对依赖项目的控制要少得多(再次,更难的维护)时,您总是需要重新打包 uber jar。

于 2016-09-02T08:10:08.757 回答
4

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

我分享了一个解决方案,让您避免明确排除所有传递依赖项,包括它到外部项目中,正如@A_DiMatteo 在他的解决方案中所解释的那样(我也同意他关于避免使用 uber jar 作为依赖项,如果不是绝对必要的话)由于某些原因 )。因此,您应该能够在不使用排除元素的情况下包含您的 uber jar 依赖项,如下所示:

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

前提:我的目标是在我的存储库中提供uber(没有在 pom 上声明传递依赖)和jar。所以我的解决方案“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插件在模块上附加带有“uber”分类器的新工件:

<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 都将上传到存储库!这里的目标应该是只上传薄 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”开始,如果您想避免在存储库上提供瘦 jar,则应避免在第 1 点上在 maven-shade-plugin 配置 中指定finalName ,因此也应避免使用build-helper-maven-plugin插件,因为没有不是要附加的新工件。这样做,部署模块,你将只有目标/上的 uber jar 作为默认值(没有分类器):

7M  something-0.1.0.jar

您还应该跳过上传,否则您还会在这里上传两个胖罐子(something-0.1.0.jarsomething-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插件,所有工件都被排除在部署之外,而这里的目标是只排除一个特定的工件。在我的 fork 中,我引入了“skipAttachedArtifacts”配置参数,以便指定要从部署中排除的附加工件。

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

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

于 2018-07-20T13:24:45.443 回答