我知道这对于有经验的编码人员来说可能是一个愚蠢的问题。但是我有一个库(一个 http 客户端),我的项目中使用的一些其他框架/jar 需要它。但它们都需要不同的主要版本,例如:
httpclient-v1.jar => Required by cralwer.jar
httpclient-v2.jar => Required by restapi.jar
httpclient-v3.jar => required by foobar.jar
类加载器是否足够智能以某种方式将它们分开?很可能不是?类加载器如何处理这个问题,以防三个 jar 中的类都相同。加载了哪一个,为什么?
Classloader 是只拾取一个 jar 还是任意混合类?例如,如果一个类是从 Version-1.jar 加载的,那么从同一个类加载器加载的所有其他类都将进入同一个 jar 吗?
你如何处理这个问题?
是否有一些技巧可以以某种方式将 jar 包“合并”到“required.jar”中,以便 Classloader
将它们视为“一个单元/包”,或者以某种方式链接?
最佳答案
类加载器相关的问题是一个相当复杂的问题。 在任何情况下,您都应该记住一些事实:
应用程序中的类加载器通常不止一个。引导类加载器委托(delegate)给适当的。当您实例化一个新类时,会调用更具体的类加载器。如果它没有找到对您尝试加载的类的引用,它会委托(delegate)给它的父类,依此类推,直到您到达引导类加载器。如果它们都没有找到对您尝试加载的类的引用,则会收到 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);
我总是发现类加载器自定义是一项棘手的任务。我宁愿建议避免多次 尽可能不兼容的依赖项。
关于Java、Classpath、Classloading => 同一个 jar/项目的多个版本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6105124/