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

Maven shaded jar used as external project dependency

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

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

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

经典场景是:

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


附带说明:将 uber-jar 作为项目的依赖项不是一个好的做法:它只会使维护更加困难,因为您无法通过 dependencyManagementdependencies依赖项目的顺序。因此,只要依赖项(其中一个传递项)需要维护(更改版本等)并且对依赖项目的控制更少(同样,更难维护),您将始终需要重新打包 uber jar。


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

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

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

Premise: my goal was to provide both uber ( without transitive dependency declared on pom ) and thin jars on my repository. So my solution "A" is based on this scenario and currently has the limit that the shaded jar is uploaded 2 times on repository.

  • To provide only the uber jar see "B" solution below
  • For a possible solution for "A" limit see the UPDATE section at the end

A) 在存储库上提供精简和超级 jar

1- 在你的源项目上配置你的something模块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>

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

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

WARN: Executing then the maven deploy phase both jars will be uploaded on repository! The target here should be to upload only the thin jar skipping deploy for shaded jar in order to leave it as a local artifact ( See the UPDATE section at the end for a possible fix )

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 点指定 finalName 在 maven-shade-plugin 配置上,因此也避免使用 build-helper-maven-plugin 插件,因为没有要附加的新工件。 这样做,部署模块你将只有 target/ 上的 uber jar 作为默认 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 fork 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>

Currently using the maven-deploy-plugin plugin all artifacts are excluded from deploy while target here is to exclude only a specific one. On my fork I've introduced the "skipAttachedArtifacts" configuration parameter in order to specify attached artifacts to exclude from deploy.

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

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