【发布时间】:2012-12-05 04:50:50
【问题描述】:
眼前的情况并不像标题所暗示的那么简单。
通过 JWS 运行的 Java 1.6_17。
我有一个类,比如说MyClass,它的实例成员变量之一是来自错误的第 3 方库的类型,在该类初始化期间,它动态尝试使用 Class.forName(String) 加载它自己的一些类。在其中一种情况下,它碰巧动态调用:Class.forName("foo/Bar")。此类名称不遵循二进制名称的 JLS,最终导致 java.lang.NoClassDefFoundError: foo/Bar。
我们有一个自定义的ClassLoader,我已经向ClassLoader.findClass(String) 和ClassLoader.loadClass(String) 添加了一个清理方法来解决这个问题。
我可以这样称呼:
myCustomClassLoader.findClass("foo/Bar")
然后加载类没有任何问题。但是即使我提前加载了类,我仍然会在以后得到异常。这是因为在 MyClass 的初始化期间,它指的是 Bar - 他们的 代码最终在某个静态块中调用 Class.forName("foo/Bar")。如果它尝试使用的 ClassLoader 是我的自定义类加载器,这实际上是可以的。但事实并非如此。是com.sun.jnlp.JNLPClassLoader 没有做这样的卫生,所以我的问题。
我已确保将Thread.currentThread().getContextClassLoader() 设置为我的自定义类加载器。但这(如您所知)没有效果。我什至把它设置为我在main() 做的第一件事,因为我读了一些东西,MyClass.class.getClassLoader() - 是 JNLPClassLoader。如果我可以强制它不是 JNLPClassLoader 而是使用我的,问题就解决了。
如何通过在类初始化期间进行的静态 Class.forName("foo/Bar") 调用来控制使用哪个 ClassLoader 来加载类?我相信如果我可以强制MyClass.class.getClassLoader() 返回我的自定义类加载器,我的问题就会得到解决。
如果有人有想法,我愿意接受其他选择。
TL;DR:帮助我强制所有 MyClass 引用的第三方库中的 Class.forName(String) 调用 - 使用我选择的类加载器。
【问题讨论】:
-
“来自错误的 3rd 方库” 最终最好的策略是替换该 API。
-
@AndrewThompson 可能会这样。我希望它不会。因此,如果有人有任何想法 - 我全神贯注!
-
我做了类似的事情,创建了一个引导类并使用 URLClassLoader 从那里加载我们所有的外部库。当 boostrap 类启动时,它们不在类路径中,因此他们看到的唯一类加载器是自定义类加载器。不是答案,因为我不知道它是否适用于 JWS。我们这样做是为了在运行时加载插件库。
标签: java classloader jnlp java-web-start dynamic-class-loaders