java - Gradle 能否以任何方式帮助解决 jar hell?

标签 java gradle dependency-management transitive-dependency conflicting-libraries

这里是 Java 8。

假设有一个旧版本的 widget 库,使用 Maven 坐标 widgetmakers:widget:1.0.4,其中定义了一个类,如下所示:

public class Widget {
    private String meow;

    // constructor, getters, setters, etc.
}

岁月流逝。此 widget 库的维护者决定 Widget 永远不应该 meow,而是应该 bark .因此,一个新的版本发布了,Maven 坐标 widgetmakers:widget:2.0.0Widget 看起来像:

public class Widget {
    private Bark bark;

    // constructor, getters, setters, etc.
}

现在我要构建我的应用程序 myapp。而且,想要使用我所有依赖项的最新稳定版本,我这样声明我的依赖项(在 build.gradle 内):

dependencies {
    compile (
        ,'org.slf4j:slf4j-api:1.7.20'
        ,'org.slf4j:slf4j-simple:1.7.20'
        ,'bupo:fizzbuzz:3.7.14'
        ,'commons-cli:commons-cli:1.2'
        ,'widgetmakers:widget:2.0.0'
    )
}

现在假设这个(虚构的)fizzbuzz总是依赖于 widget 库的 1.x 版本,其中 Widget喵喵

现在,我在我的编译类路径中指定了 2 个版本的 widget:

  1. widgetmakers:widget:1.0.4fizzbuzz 库引入,作为它的依赖;和
  2. widgetmakers:widget:2.0.0 我直接引用

很明显,根据哪个版本的 Widget 首先加载类,我们将有一个 Widget#meow 或一个 Widget#bark .

Gradle 是否提供任何工具来帮助我解决这个问题?有什么方法可以引入同一个类的多个版本,并配置 fizzbuzz 类使用旧版本的 Widget,而我的类使用新版本?如果没有,我能想到的唯一解决方案是:

  1. 我也许能够完成某种基于着色和/或 fatjar 的解决方案,也许我将所有依赖项作为包放入 myapp/bin 下,然后为它们提供不同的版本-前缀。不可否认,我在这里没有看到一个明确的解决方案,但我确信有些事情是可行的(但完全是 hacky/nasty)。或者……
  2. 仔细检查我的整个依赖关系图,确保我所有的传递依赖关系不相互冲突。在这种情况下,对我来说,这意味着要么向 fizzbuzz 维护者提交拉取请求,以将其升级到最新的 widget 版本,要么不幸地降级 myapp 使用较旧的 widget 版本。

但 Gradle(到目前为止)对我来说很神奇。所以我问:这里有什么 Gradle 魔法可以帮到我吗?

最佳答案

不知道 Gradle 的细节,因为我是 Maven 的人,但这无论如何更通用。你基本上有两个选择(而且都是 hacky):

  1. ClassLoader 魔法。不知何故,您需要说服您的构建系统加载两个版本的库(祝您好运),然后在运行时,使用具有旧版本的 ClassLoader 加载使用旧版本的类。我已经这样做了,但这很痛苦。 (像 OSGI 这样的工具可能会减轻一些这种痛苦)
  2. 包装着色。重新打包使用旧版本库 B 的库 A,使 B 实际上位于 A 内部,但带有特定于 B 的包前缀。这是常见的做法,例如春船its own version of asm .在 Maven 方面,maven-shade-plugin这样做,可能有一个 Gradle 等价物。或者你可以使用 ProGuard ,Jar 操纵的 800 磅 gorilla 。

关于java - Gradle 能否以任何方式帮助解决 jar hell?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36940405/

相关文章:

Java Swing FocusTraversalPolicy 问题

java - Android 中的 fragment 事务错误不适用

gradle - Groovy 中的测试类在 Kotlin 中看不到测试类

java - 如何从 spring-boot-starter-parent 中排除特定的依赖项

c# - 如何在不依赖于实现的情况下使用接口(interface)的实现?

rpm - rpmbuild 时可以忽略某些特定的自动检测依赖项吗

java - 在java中将jpanel添加到jpanel中

java - Gradle 构建错误

java - 具有 firebase 依赖项的 Android gradle 构建有警告(忽略 httpclient)

java - Libgdx 平铺 map 无法正确显示