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 主旨演讲 中的建议,只在你的版本中进行增量更改,而不是破坏性更改,那么这将大大减少意外版本选择导致的破坏性冲突。

如果你确实想同时加载库的多个版本,Java 类加载器架构允许你这样做,但这需要一个自定义类加载器和一些架构上的规范。在这种情况下,你创建一个接口(或协议),它是由你的基本类加载器加载的,然后使用后委托类加载器,只在该类加载器中加载类的实现。后委托允许每个独立的“插件”加载任何它需要的,但可以通过基本层接口与应用程序通信。正如我所说,这可以工作,但需要大量的设置和规范,并且有一些工作方式的限制,所以通常只在你预期产品将具有高度依赖冲突而有强烈“插件”类型架构贡献时才值得这样做。OSGi 是解决此问题的另一种方法。在 Clojure 中实现这些都不特别有趣。

JVM 团队似乎非常不愿意让用户加载同一类的多个版本。他们甚至到了检测重命名,通过附加版本来防止用户将版本嵌入模块。不知道为什么。

我有的问题,有没有一种模式,tools.deps 可以在冲突时直接失败,并使用显式声明来指定版本?
在 tools.deps 中,始终使用顶级依赖版本,而不考虑传递依赖中指定的任何其他版本。因此,您始终可以在顶级显式声明依赖以“锁定”特定版本。

虽然有可能添加一些影响版本选择的选择,但这会让其他人很难了解在使用您的库时该做什么,所以我相当犹豫将此作为 clj 中浮出表面的东西。

我甚至不确定“冲突”应该代表什么意思 - 如果你只是在讨论deps树中存在相同库的多个版本,这几乎发生在每个非平凡的deps集合中(即使只是解决要包含的Clojure的版本)。
...