默认情况下这是不可能的,jigsaw也无法帮助。然而,仍有希望。
在 JVM 中,默认的类加载器设置使用 Java 类路径。类路径是搜索(按顺序)类所在位置的列表。因此,如果类路径上有同一依赖项的两个版本,则会加载类路径中先发现的版本。
Java 9 中引入的模块系统引入了“模块”的新概念和新的“模块路径”,该路径指定要加载的基本模块集。模块提供了新的封装级别,防止外部使用实现的非公共部分,这可能很有用。然而,模块系统没有版本或版本选择的概念,因此包含同一模块多个版本的问题仍然存在。模块加载器会检测并对此问题提出抱怨,而不是您从类路径加载所得到的静默选择。但是,它并没有“修复”此问题。
当您使用Maven(或基于Maven的依赖解析系统,如Leiningen或Boot)时,您是在让Maven检查传递依赖的树,并从中选择一个版本来使用。在Maven中,选择基本上基于对传递树进行广度优先遍历后遇到的第一版本。tools.deps使用其自己的选择算法,优先选择依赖项的最新版本(同时仍然构建逻辑上合理的依赖树)。如果您遵循Rich在 Spec-ulation演讲中的建议,只在版本中进行增量且不破坏性的更改,那么这将大大降低意外版本选择导致的破坏性冲突。
如果您确实需要在同一时刻加载同一库的多个版本,Java类加载器架构确实允许您这么做,但这需要自定义类加载器和一些架构规范。在这种情况下,您创建一个接口(或协议),该接口从您的基类加载器加载,然后使用后续委托类加载器,只在那个类加载器中加载类的实现。后续委托允许每个独立的“插件”加载它需要的东西,但然后通过基本的接口与应用程序通信。正如我说的,这可行,但需要大量的设置和规范,并且对它的工作方式有一些限制,所以通常只有在您非常期望产品中包含具有高度依赖冲突可能性的“插件”型架构时才值得这么做。OSGi是解决这个问题的另一种方法。在Clojure中实现这些都不太愉快。