【问题标题】:Multiple versions of the same dependency in MavenMaven中相同依赖项的多个版本
【发布时间】:2014-07-25 18:51:00
【问题描述】:

是否可以在 Maven 存储库中声明同一依赖项的多个版本

我同时需要这些依赖项:

    <dependency>
        <groupId>org.bukkit</groupId>
        <artifactId>craftbukkit</artifactId>
        <version>1.7.9-R0.2</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>org.bukkit</groupId>
        <artifactId>craftbukkit</artifactId>
        <version>1.7.2-R0.3</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>org.bukkit</groupId>
        <artifactId>craftbukkit</artifactId>
        <version>1.6.4-R2.0</version>
        <scope>compile</scope>
    </dependency>

因为它们每个都包含我关心的不同包:

org.bukkit.craftbukkit.v1_6_R3

org.bukkit.craftbukkit.v1_7_R1

org.bukkit.craftbukkit.v1_7_R3

如果我按照第一个sn-p的方式声明依赖,只有最后一个会生效。有没有办法在 Maven 中实现这一点?

@Edit 任何解决方法,也许?

【问题讨论】:

  • 为什么需要这样做?如果 Maven 允许这种行为,您将拥有一个不可预测的类路径,其中包含相同类的多个副本。 Java 不会在运行时对类进行版本控制,这意味着 Maven 的限制是一件好事!
  • 在我开始使用 Maven 之前,我曾经在类路径中包含多个版本的同一个库,我没有遇到任何问题。我需要它来提供对 Bukkit 的向后兼容性,它是我运行插件的 Minecraft 游戏服务器。
  • 好吧,我猜你从来没有为 Bukkit 写过插件 :)
  • @wassup 这对我来说毫无意义,抱歉……如果我支持产品的多个版本,我会在我的源代码控制系统中使用不同的分支并分别构建每个版本。这样每个人都有自己独特的依赖版本集。关键是在运行时只有一个类的副本。如果您使用同一个 jar 的多个版本,您最终会遇到一个棘手的问题,即您并不真正知道 java 类加载器使用的是哪一个。这是 Maven 通过坚持一个版本来防止的问题。
  • 你好 Mark - 我可以给你一个需要多个版本的用例。在我们公司,我们有一组在 Apache Servicemix 上运行的应用程序。 Servicemix 的有趣之处在于,所有内容都配置了功能文件,我们会调用需要安装的捆绑包。当 servicemix 启动时,它可以直接从 maven 存储库中提取这些捆绑包——这非常有效,直到我们进入不允许连接到我们公司的 maven 存储库的认证和生产环境。

标签: maven


【解决方案1】:

没有。 Maven 只会解决您模块中的一个依赖项,并且会忽略其他版本以避免任何冲突。即使在整个依赖层次结构中使用相同依赖的多个版本,Maven 也会使用“依赖树中最近的”策略选择一个版本。

可以使用不同的profiles 指定不同的依赖版本。对于 Bukkit 的每个版本,都可以定义和激活配置文件。不过,如果您激活了多个配置文件,则只会使用 一个 版本。

<profiles>
    <profile>
        <id>Bukkit_1_7_9_R02</id>
        <activation>
            ...
        </activation>
        <dependencies>
            <dependency>
                <groupId>org.bukkit</groupId>
                <artifactId>craftbukkit</artifactId>
                <version>1.7.9-R0.2</version>
                <scope>compile</scope>
            </dependency>
        </dependencies>
    </profile>
    <profile>
        <id>Bukkit_1_7_2_R03</id>
        <activation>
            ...
        </activation>
        <dependencies>
            <dependency>
                <groupId>org.bukkit</groupId>
                <artifactId>craftbukkit</artifactId>
                <version>1.7.2-R0.3</version>
                <scope>compile</scope>
            </dependency>
        </dependencies>
    </profile>
    ...
</profiles>

【讨论】:

【解决方案2】:

尝试欺骗maven:

<dependency>
    <groupId>org.bukkit</groupId>
    <artifactId>craftbukkit</artifactId>
    <version>1.7.9-R0.2</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.bukkit.</groupId>
    <artifactId>craftbukkit</artifactId>
    <version>1.7.2-R0.3</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.bukkit..</groupId>
    <artifactId>craftbukkit</artifactId>
    <version>1.6.4-R2.0</version>
    <scope>compile</scope>
</dependency>

【讨论】:

  • 这是最好的解决方案。
  • 感谢您的提示!
  • @Dmitri 你能解释一下这个作弊行家是怎么做的吗?为什么你在 groupId 中添加了一个额外的点?最终结果会是什么?应该期待什么?
  • 这很有趣。我猜它可以工作,因为根据maven docs,点被转换为存储库中的目录分隔符。操作系统可以很好地处理文件系统路径中的多个斜杠。例如Windows 将C:\path\\with\\\slashes.txt 之类的路径解析为文件C:\path\with\slashes.txt
  • 这是怎么工作的!?!谢谢大声笑!
【解决方案3】:

这里是the Maven documentation的相关部分,它解释了当存在多种可能性时,Maven如何选择依赖的版本:

依赖中介 - 这决定了工件的版本 当遇到多个版本作为依赖项时将被选择。 Maven 选择“最近的定义”。也就是说,它使用的版本 依赖关系树中与您的项目最接近的依赖关系。 您始终可以通过在您的 项目的POM。请注意,如果两个依赖版本相同 在依赖树的深度,第一个声明获胜。 “最近的 定义”意味着使用的版本将是最接近的版本 你的项目在依赖树中。考虑这棵树 依赖:

A
├── B
│   └── C
│       └── D 2.0
└── E
    └── D 1.0

在文本中,A、B、C 的依赖定义为 A -> B -> C -> D 2.0 和 A -> E -> D 1.0,那么构建 A 时将使用 D 1.0,因为路径从 A 到 D 到 E 更短。你 可以在 A 中显式添加对 D 2.0 的依赖项以强制使用 D 2.0,如下图:

A
├── B
│   └── C
│       └── D 2.0
├── E
│   └── D 1.0
│
└── D 2.0      

【讨论】:

    【解决方案4】:

    不,通常情况下,您不能依赖同一工件的 2 个版本。
    但是您可以包含它们,以便它们最终出现在生成的应用程序中。

    该要求有时是有效的 - 例如,当该库的维护很差时,他们重命名了一些包并将其作为同一工件的次要版本发布。然后,其他项目将其作为 3rd 方依赖项,需要不同 FQCN 下的相同类。

    对于这种情况,您可以使用maven-shade-plugin

    • 创建一个具有单个依赖项的 maven 项目,这是您需要的版本之一。
    • 添加shade 插件并让它创建一个带阴影的jar。它基本上会将类重新包装在不同的工件 G:A:V 下。
    • 为您需要的所有版本执行此操作。
    • 您可以使用分类器来区分阴影版本。
    • 在您的项目中,依赖这些工件。
    • 最后,排除原始依赖项,给它们“提供”的范围。

    您可以使用相同的不同变体,最终将这些类放到您的类路径中。例如,使用dependency:copy-dependency 插件/目标,并在构建期间将该 jar 安装到本地存储库。或者将类直接解压缩到您的${project.build.outputDirectory}(目标/类)中。

    【讨论】:

      【解决方案5】:

      我还是个新手,但是我在使用axis2时遇到的问题是各个模块有时需要较早的版本,因为它们对类进行了更改,因此顶级依赖项仅捕获了大约一半他们。其余的我不得不单独更正 pom 以明确依赖于不同的版本。

      也许这种方法也适合您?让插件具有针对其特定依赖项的模块化组件。

      【讨论】:

      • 如果我对情况的理解正确,我认为您可以在自己的 pom 中的 dependencyManagement 部分下指定一次。这将强制将该版本拉入您的项目/程序集中。
      【解决方案6】:

      这就是我解决它的方法。仅供参考:就我而言,我正在构建一个 RPM。

      我使用maven-dependency-plugin 将被忽略的旧依赖项复制到构建目录中的文件夹,然后将该文件复制到暂存区域,以便将其包含在 RPM 中。

      这里是复制旧依赖的代码:

        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-dependency-plugin</artifactId>
          <version>3.1.1</version>
          <executions>
            <execution>
              <id>copy-dependencies</id>
              <phase>prepare-package</phase>
              <goals>
                <goal>copy</goal>
              </goals>
              <configuration>
                <artifactItems>
                  <artifactItem>
                    <groupId>some.package.group.id</groupId>
                    <artifactId>someartifact-id</artifactId>
                    <version>1.2.3</version>
                    <overWrite>false</overWrite>
                    <outputDirectory>${project.build.directory}/older-dependencies</outputDirectory>
                  </artifactItem>
                </artifactItems>
              </configuration>
            </execution>
          </executions>
        </plugin>
      

      后来在构建我的 RPM 期间,我将这个 scriptlet 包含在我的 rpm-maven-pluginconfiguration 部分中。这会将文件复制到 RPM 的暂存区:

      <installScriptlet>
        <script>cp ${project.build.directory}/older-dependencies/* ${project.build.directory}/rpm/${artifactId}/buildroot${installBase}/</script>
      </installScriptlet>
      

      【讨论】:

        猜你喜欢
        • 2016-05-24
        • 1970-01-01
        • 2012-04-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多