我知道对于经验丰富的编码人员来说,这可能是一个愚蠢的问题。但是我有一个库(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或以某种方式链接为“一个单元/包装” ?
Classloader
与类加载器相关的问题是一个非常复杂的问题。无论如何,你都应该记住一些事实:
一个应用程序中的类加载器通常不止一个。引导程序类加载器委托给相应的。当你实例化一个新类时,将调用更具体的类加载器。如果找不到对你尝试加载的类的引用,它将委派给其父类,依此类推,直到你进入引导类加载器。如果它们都找不到你要加载的类的引用,则会得到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);
我总是发现类加载器定制是一项棘手的任务。如果可能,我宁愿避免使用多个不兼容的依赖项。