Java、Classpath、Classloading => 同一个 jar/项目的多个版本

新手上路,请多包涵

我知道这对于有经验的程序员来说可能是个愚蠢的问题。但是我有一个库(一个 http 客户端),我的项目中使用的其他一些框架/jar 需要它。但是它们都需要不同的主要版本,例如:

 httpclient-v1.jar => Required by cralwer.jar
httpclient-v2.jar => Required by restapi.jar
httpclient-v3.jar => required by foobar.jar

类加载器是否足够智能以某种方式将它们分开?很可能不是?类加载器如何处理这个,以防所有三个罐子中的类相同。加载了哪一个,为什么?

Classloader 只拾取一个 jar 还是任意混合类?因此,例如,如果一个类是从 Version-1.jar 加载的,那么从同一个类加载器加载的所有其他类都将全部放入同一个 jar 中吗?

你如何处理这个问题?

是否有一些技巧以某种方式将罐子“合并”到“required.jar”中,以便它们被 Classloader 视为“一个单元/包”,或以某种方式链接?

原文由 jens 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 451
2 个回答

与类加载器相关的问题是一个相当复杂的问题。在任何情况下,您都应该记住一些事实:

  • 应用程序中的类加载器通常不止一个。引导类加载器委托给适当的。当您实例化一个新类时,将调用更具体的类加载器。如果它没有找到对您尝试加载的类的引用,它将委托给它的父类,依此类推,直到您到达引导类加载器。如果它们都找不到对您尝试加载的类的引用,您将得到一个 ClassNotFoundException。

  • 如果你有两个具有相同二进制名称的类,可由同一个类加载器搜索,并且你想知道你正在加载其中的哪一个,你只能检查特定类加载器尝试解析类名的方式。

  • 根据 java 语言规范,类二进制名称没有唯一性约束,但据我所知,它对于每个类加载器都应该是唯一的。

我可以想出一种方法来加载两个具有相同二进制名称的类,它涉及通过两个不同的类加载器加载它们(以及它们的所有依赖项)来覆盖默认行为。一个粗略的例子:

     ClassLoader loaderA = new MyClassLoader(libPathOne);
    ClassLoader loaderB = new MyClassLoader(libPathTwo);
    Object1 obj1 = loaderA.loadClass("first.class.binary.name", true)
    Object2 obj2 = loaderB.loadClass("second.class.binary.name", true);

我总是发现类加载器定制是一项棘手的任务。我宁愿建议尽可能避免多个不兼容的依赖项。

原文由 Luca Putzu 发布,翻译遵循 CC BY-SA 3.0 许可协议

每个类负载只选择一个类。通常是第一个发现的。

OSGi 旨在解决同一个jar的多个版本问题。 EquinoxApache Felix 是 OSGi 的常见开源实现。

原文由 Tarlog 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题