Java Classloader – 如何引用jar的不同版本

这是一个常见问题。 我正在使用2个库A.jarB.jar ,这些库依赖于同一个jar的不同版本。
假设在运行时我需要THIS.xxxjar

MY.jar -> A.jar -> THIS.1.0.0.jar -> B.jar -> C.jar -> THIS.5.0.0.jar 

我可以针对它的依赖编译特定的jar(A.jar / B.jar)但是在运行时我只能加载1个版本。 哪一个?
仅加载1个依赖项(最新版本)意味着如果库不是向后兼容的,那么我的代码可能会抛出运行时exception(那里有向后兼容的库吗?)。

无论如何,我知道像OSGi这样的东西可以解决这个问题。
我想知道解决这类问题的旧方法是什么……

非常感谢

你提到的“旧方式”(以及OSGI当然使用的一种方法)是为依赖关系的两个分支安装自己的ClassLoader。 例如,应用程序服务器就能够在同一个JVM中运行相同应用程序的较旧版本和较新版本。

了解类加载器层次结构。

在你的设置中,棘手的部分是联合点,两个分支的类在这里相遇。 两个分支都不能使用加载到另一个分支中的类。 使其工作的方法是确保只有由boot classloader(JRE类)或MY.jar的类加载器加载的类才传递给两个分支。

OSGi可以解决这个问题。 OSGi包只不过是一个带有额外元数据详细说明版本的jar。 捆绑包具有版本号,并将详细说明从属jar的版本号(或范围)。

有关更多信息,请查看Javaworld的这篇介绍性文章 。

要在没有OSGi的情况下解决这个问题,就必须手动确保使用兼容的jar进行编译和运行。 正如您所发现的那样,这不一定是一项微不足道的任务。 由于jar不一定能识别它们的版本,因此唯一可靠的方法是记录/比较校验和或签名。

许多库是向后兼容的。 但不是所有的..


旧方法是尝试仅依赖一个版本。

使用相同版本(最新版本)编译两者可能更安全。
至少你得到编译时错误,而不是运行时错误。

如果需要,您可以修改一下与旧依赖项一起使用的库…
这需要访问源…


请注意,编译时兼容性也不能保证正确的运行时行为。 这是一步,然后您可以:

  • 阅读WhatsNew文件以获取新版本的jar
  • 在互联网上查看报告兼容性问题的用户
  • 写JUnits
  • 比较两个jar子里的代码

正如KLE所提到的,默认方法是依赖于较新的版本。 没有保证,但大部分时间都有效。 可能最好的方式(虽然是一个臃肿的方式)是使用OSGI来克服它。

引用基本的“oldway”实现checkout https://github.com/atulsm/ElasticsearchClassLoader

这提供了一种处理elasticsearch客户端使用的非向后兼容版本的方法。