我急切地寻求帮助,但无法在网上找到有关此特定主题的任何信息(许多相关主题让我的特定问题未得到解答)。
具体来说,我需要能够从中央和外部代码存储库下载代码(jar)。这是由需要将其添加到类加载器的类路径以供其后使用的引导代码完成的。这是我们进入已经讨论过很多次的主题的时候。我不喜欢黑客,所以我尝试了以下方法:
尝试#1:创建一个为此目的配置的 URLClassLoader 实例,然后通过它调用代码的“其余部分”。
失败:这里有1.5个问题(一个可能是另一个原因)。一是 URLClassLoader 通常更喜欢从其父级加载内容。一些代码必须同时存在于两个版本中,可能是不同的版本。如果使用来自父级的代码,它将继续使用“外部”类加载器进行其余的加载,这不是我们想要的,即使初始加载正常。其次,一些第三方库似乎直接访问系统类加载器,无论是有意还是无意(可能从它加载的类之一中获取)。
尝试#2:创建我的 URLClassLoader 的子类,它更喜欢自己而不是父类。覆盖 loadClass、getResource、getResources、getPackage、getPackages ......以后也可以使用其他方法来确保这一点。
失败:没有帮助(足够)。该第三方代码仍然无法加载某些资源。
尝试#3创建另一个 URLClassLoader 的自定义子类,并使用 -Djava.system.class.loader=... 将其设置为系统类加载器
失败:这效果更好 - 更进一步,但尝试获取资源仍然失败。不过,这一次是不同的资源。我向所有被覆盖的方法添加了日志记录,以记录它们的调用和资源名称。大部分都找到了经常资源。有些人仍然没有,即使他们在那里(确认)。但是,即使我努力学习,我也不知道的是许多资源名称以斜杠结尾的调用。有些还有斜线,通常会出现美元符号(嵌套/内部类资源)。请求但未找到的一些示例:
com/acme/foo/bar/ClassName/ com/acme/foo/bar/ClassName/InnerClassName/
当我使用初始/引导类路径上的所有内容运行下载的代码时(并且不使用我的类加载器),一切正常 - 因此我的类加载器破坏了一些东西,但我需要它工作。
我最接近的猜测是:
第三方代码以某种方式获取了真正的系统类加载器,可能是通过它加载的某个类,然后使用它。我看不到对它的请求,它们肯定会失败,因为它没有整个类路径。
资源名称以斜线结尾的业务是由真正的系统类加载器支持的原因,但不是由我正在继承的 URLClassLoader 支持的原因。我只能猜测预期的返回 URL 以某种方式定位了以该名称为前缀的资源集合。尽管有可能,但这将很难匹配。此外,似乎一些斜杠位于分隔内部类名称的美元符号应该位于的位置,即在上面的示例中(为清楚起见添加了空格):
com/acme/foo/bar/ClassName / InnerClassName/
com/acme/foo/bar/ClassName $ InnerClassName/
请注意,我不能依靠假设它是 URLClassLoader 的子类并使用反射来调用其 addURL(URL) 方法来破解实际的系统类加载器。
有没有办法使这项工作?请帮忙!
更新
我刚刚做了一次额外的尝试。我创建了一个仅记录请求的虚拟包装类加载器(扩展 ClassLoader,而不是 URLClassLoader),然后将它们传递给父类(公共方法)或超类(受保护方法)。我将其设置为系统类加载器并手动将整个“内部”类路径添加到实际的外部类路径,然后尝试运行代码。这可以正常工作,就像没有自定义系统类加载器一样。记录的内容还发现,即使系统类加载器也为这些以斜线结尾的资源返回 null,但不是全部。我没有检查这些是否也适用于我的真实代码,但猜测它们可能 - 因为它们不是绊脚石。不知何故,自定义系统类加载器仍在被绕过。如何?
更新 2
在我的自定义系统类加载器中,我让一些类来自外部/真正的系统类加载器,例如 java.lang 中的那些。我现在怀疑我不应该有,内心的“世界”必须完全孤立。但是,与它进行通信会带来问题,而我剩下的就是反射......但不确定这是否会起作用 - 即是否可以有多个 java.lang.Class 和/或 java.lang 。目的?