19

这是一个常见的问题。我正在使用 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 个依赖项(最新版本)意味着如果库不向后兼容(是否有向后兼容的库?),我的代码可能会引发运行时异常。

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

非常感谢

4

5 回答 5

7

您提到的“旧方法”(OSGI 肯定会在后台使用的一种)是为您的依赖项的两个分支安装您自己的 ClassLoader。例如,这就是应用程序服务器能够在同一 JVM 中运行同一应用程序的旧版本和新版本的方式。

阅读有关类加载器层次结构的信息。

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

于 2009-10-12T15:18:10.920 回答
4

OSGi 可以解决这个问题。OSGi 包只不过是一个带有附加元数据详细版本的 jar。一个包有一个版本号,并且会详细说明依赖 jar 的版本号(或范围)。

查看这篇介绍性的 Javaworld 文章以获取更多信息。

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

于 2009-10-12T09:50:33.237 回答
1

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


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

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

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


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

  • 读取新版本 jar 的 WhatsNew 文件
  • 在 Internet 上查找报告兼容性问题的用户
  • 编写 JUnit
  • 比较两个罐子中的代码
于 2009-10-12T09:46:38.400 回答
1

正如 KLE 所提到的,默认的方法是依赖于较新的版本。无法保证,但大多数情况下这是有效的。可能最好的方法(虽然是一个臃肿的)是使用 OSGI 来克服它。

于 2009-10-12T09:51:29.010 回答
1

要参考基本的“旧方式”实施结帐https://github.com/atulsm/ElasticsearchClassLoader

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

于 2016-02-13T19:20:42.000 回答