一尘不染

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

java

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

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

类加载器是否足够智能以某种方式将它们分开?很有可能不是吗?万一所有三个jar中的Class都相同,Classloader如何处理这个问题。加载哪一个?为什么?

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

你如何处理这个问题?

是否有某种技巧可以以某种方式将jar“合并”到“ required.jar”中,从而使jar被Classloader或以某种方式链接为“一个单元/包装” ?


阅读 430

收藏
2020-03-05

共1个答案

一尘不染

与类加载器相关的问题是一个非常复杂的问题。无论如何,你都应该记住一些事实:

  • 一个应用程序中的类加载器通常不止一个。引导程序类加载器委托给相应的。当你实例化一个新类时,将调用更具体的类加载器。如果找不到对你尝试加载的类的引用,它将委派给其父类,依此类推,直到你进入引导类加载器。如果它们都找不到你要加载的类的引用,则会得到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);

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

2020-03-05