2024年Clojure状态调查!中分享您的想法。

欢迎!请参阅关于页面,了解更多关于如何使用本站的信息。

0
tools.deps

不可能使用同一传递依赖的不同版本。
这是否可能?
Java 9 (jigsaw) 能帮助吗?

1 个答案

+2

被选中
 
最佳答案

默认情况下无法实现,而且 jigsaw 也无能为力。但是,仍有一线希望。

JVM 中的默认类加载器设置使用 Java 类路径。类路径是为查找类的位置(按顺序)的地点列表。因此,如果类路径上存在同一依赖项的两个版本,则会加载类路径上第一个出现的版本。

Java 9 中引入的模块系统引入了“模块”这一新概念,以及指定要加载的模块基本集合的新“模块路径”。模块提供了新的封装级别,防止外部使用实现的非公开部分,这可能很有用。然而,模块系统没有版本或版本选择的概念,因此包含同一模块多个版本的问题仍然存在。模块加载器将检测并抱怨这个问题,而不是像类路径加载那样得到一个无声的选择。但它并没有做什么“修正”。

当你使用Maven(或基于Maven的解决系统如Leiningen或Boot)时,你就要求Maven检查传递依赖的树,并选择一个版本来使用。在Maven中,选择基本上是基于对传递树的广度优先遍历中首先遇到的版本。tools.deps使用自己的选择算法,优先选择依赖项的最新版本(同时仍然构建逻辑上合理的依赖项树)。如果你遵循Rich在《Spec-ulation首脑演讲》(https://github.com/matthiasn/talk-transcripts/blob/master/Hickey_Rich/Spec_ulation.md)中的建议,只对你版本中进行增加性修改而不是破坏性修改,那么这将大大减少由意外版本选择引起的破坏性冲突。

如果您确实想在同一时间加载库的多个版本,Java类加载器架构允许您这样做,但这需要自定义类加载器和一些架构纪律。在这种情况下,您创建一个接口(或协议),该接口是从您的基石类加载器加载的,然后使用后委托类加载器,并只在那个类加载器中加载类的工作实现。后委托允许每个独立的“插件”加载它所需要的任何内容,然后再通过基石级别的接口与应用程序通信。正如我所说的,这是可行的,但是需要大量的设置和纪律,并且对工作方式有一些限制,因此只有在您构建的一个产品中,强烈期望有“插件”类型架构和高度依赖冲突可能性时才值得一试。OSGi也是解决这个问题的一种方法。在Clojure中实现这两种方法都不太有趣。

JVM团队似乎非常反对让人们加载相同类别的多个版本。他们甚至去识别重命名,在版本附加的情况下阻止人们将版本嵌入模块中。不知道为什么。

我有一些疑问,tools.deps的状态是否可以失败在可能的冲突中,并使用显式声明指定这种情况下的版本?
在tools.deps中,顶级依赖项版本在各种传递依赖项中指定的任何其他版本中始终使用。因此,您始终可以在顶级显式声明依赖项,“锁定”特定版本。

有一些选项可以影响版本选择是可能的,但那时就很难向他人传达在使用您的库时应该做什么,所以我对将其作为在clj中呈现的内容感到相当犹豫。

我不太确定“冲突”应该意味着什么——如果您只是在说deps树中出现的同一库的多个版本,这在基本上每个非平凡集的依赖项(即使仅仅是解决包含Clojure的版本)中都会发生。
...