【发布时间】:2016-05-25 12:24:34
【问题描述】:
我们正在尝试调试 WebStart 的一个不可重现的问题,即对 Jars 内资源的访问将“随机”失败。可能每运行 1000 个应用程序就有一个会以这个错误结束,这可能发生在从 jar 读取资源的任何地方。
在 Google 和 Java Bug 数据库中搜索没有任何相似之处(或者至少没有任何帮助)。
我们正试图通过“检测”应用程序来获取更多关于客户端发生的情况的信息,以便我们跟踪对ClassLoader.getResource(String) 的所有调用(包括间接通过ClassLoader.getResourceAsStream(String))。在不更改应用程序代码的情况下,我创建了一个“启动器”,它将使用自定义类加载器运行整个应用程序。
不幸的是,我的 ClassLoader 似乎被绕过了。我没有看到任何预期的 System.out 输出。这是我尝试过的:
private static final class MyClassLoader extends ClassLoader {
private MyClassLoader() {
super(TheClassThatMainIsIn.class.getClassLoader());
}
@Override
public URL getResource(String name) {
System.out.println("getResource("+name+")");
// Snip
return super.getResource(name);
}
@Override
public InputStream getResourceAsStream(String name) {
System.out.println("getResourceAsStream("+name+")");
final URL url = getResource(name);
try {
return url != null ? url.openStream() : null;
} catch (final IOException e) {
return null;
}
}
}
public static void main(String[] args) {
System.out.println("Starting MyRealApp Launcher ...");
final MyClassLoader loader = new MyClassLoader();
try {
Class<?> realAppClasss = loader.loadClass("MyRealAppClass");
Method main = realAppClasss.getMethod("main", String[].class);
main.invoke(null, (Object) args);
} catch (final RuntimeException e) {
throw e;
} catch (final Error e) {
throw e;
} catch (final InvocationTargetException e) {
final Throwable cause = e.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
}
if (cause instanceof Error) {
throw (Error) cause;
}
throw new UndeclaredThrowableException(cause);
} catch (final Throwable t) {
throw new UndeclaredThrowableException(t);
}
}
我在这里做错了什么?
【问题讨论】:
-
你是否覆盖了 findClass() 和 loadClassData?
-
不,我不会覆盖那些;我对“课程”不感兴趣;只是“资源”。我是不是该?如果是这样,除了将调用传递给基类之外我应该做什么?
-
不,你不应该这样做。我第一次阅读时误解了你的问题。你在做什么似乎是正确的。我建议在您的项目中包含 ClassLoader 源代码,使用调试器逐步执行此操作,以查看它为什么不调用您的覆盖方法。
-
Java 中的 CL 用于委托策略。在加载类之前,CL 会询问其父类 X 的字节定义是否已知。只有当没有祖先知道类字节时,实际的 CL 才会加载类定义。在您的情况下,似乎
MyRealAppClass是在应用程序启动时加载的,因此loadClass调用被委托给系统CL,它还负责@Gamlor 已经指出的资源加载-您可以尝试-verbose:class看看之前是否加载过
标签: java classloader