【问题标题】:How can I safely solve this Java context classloader problem?如何安全地解决这个 Java 上下文类加载器问题?
【发布时间】:2009-12-06 16:29:59
【问题描述】:

我的数百名用户中只有一个无法启动我的 Java 桌面应用程序。对他来说只有大约三分之一的时间才开始。另外三分之二的时间在启动时抛出 NullPointerException:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at java.util.Hashtable.put(Hashtable.java:394)
    at javax.swing.JEditorPane.registerEditorKitForContentType(JEditorPane.java:1327)
    at javax.swing.JEditorPane.registerEditorKitForContentType(JEditorPane.java:1309)
    at javax.swing.JEditorPane.loadDefaultKitsIfNecessary(JEditorPane.java:1387)
    at javax.swing.JEditorPane.getKitTypeRegistry(JEditorPane.java:1344)
    at javax.swing.JEditorPane.getEditorKitClassNameForContentType(JEditorPane.java:1340)
    at javax.swing.JTextPane.<init>(JTextPane.java:76)
    at myapp.Launcher$1.run(Launcher.java:13)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:633)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

我跟踪堆栈跟踪发现原因是

Thread.currentThread().getContextClassLoader()

在 JEditorPane 中返回 null。

谷歌搜索显示,这是一个影响少数人的零星、非常罕见且神秘的问题。

我的问题是,我可以做些什么来解决这个问题?如果我在创建 EditorPane 之前调用它,这可能会起作用:

Thread.currentThread().setContextClassLoader(MyClass.class.getClassLoader());

但我并没有像我想的那样真正了解类加载器(而且我试图更好地理解它们)。我觉得在 EDT 中更改 contextClassLoader 可能会产生不好的后果。

任何想法我能做什么?

编辑:我与非常了解 Java 类加载器的人有过一些通信。这似乎是一个模糊的 ClassLoader 竞争条件。也就是说,Java 中的一个错误。

【问题讨论】:

  • 是否有机会升级用户的 Java 运行时?
  • @Tamás,这是一个 Mac 应用程序。我让他尝试最新的 Mac Java 更新。

标签: java classloader contextclassloader


【解决方案1】:
Thread.currentThread().getContextClassLoader()

如果JEditorPane.registerEditorKitForContentType 中的代码在上述代码中没有检查空返回值,这是JEditorPane 中的错误。注意MyClass.class.getClassLoader()may also return null。您唯一可以依靠的是system ClassLoader

为调用设置上下文ClassLoader 的模式通常如下所示:

Thread thread = Thread.currentThread();
ClassLoader old = thread.getContextClassLoader();
thread.setContextClassLoader(fooClassLoader);
try {
  // do call that depends on context ClassLoader
} finally {
  thread.setContextClassLoader(old);
}

应该通过setContextClassLoader 设置的值将取决于使用它的代码的意图以及您正在运行的ClassLoader 框架的设计。

在独立应用程序中,您可能只需使用这个ClassLoader(将引用传递给当前类)就可以逃脱:

private ClassLoader findClassLoaderForContext(Class<?> c) {
  ClassLoader context = Thread.currentThread().getContextClassLoader();
  ClassLoader me = c.getClassLoader();
  ClassLoader system = ClassLoader.getSystemClassLoader();
  return (context == null) ? (me == null) ? system : me : context;
}

在对 ClassLoader 敏感的插件框架中(Java EE 服务器就是一个很好的例子),了解加载方案的性质和用法是值得的。

【讨论】:

  • 我尝试了您为设置调用的上下文类加载器提供的模式。我喜欢它,因为它不会因为 contextclassloader 的其他用途而搞砸事情。
猜你喜欢
  • 1970-01-01
  • 2011-02-25
  • 1970-01-01
  • 1970-01-01
  • 2019-09-10
  • 2020-06-29
  • 1970-01-01
  • 2020-11-30
  • 1970-01-01
相关资源
最近更新 更多