簡體   English   中英

如何安全地解決此Java上下文類加載器問題?

[英]How can I safely solve this Java context classloader problem?

我的數百名用戶中只有一個在啟動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 ClassLoaders的人有一些通信。 這似乎是一個模糊的ClassLoader競爭條件。 也就是說,Java中的一個錯誤。

Thread.currentThread().getContextClassLoader()

如果JEditorPane.registerEditorKitForContentType中的代碼未檢查上述代碼中的null返回值,則這是JEditorPane的錯誤。 請注意, MyClass.class.getClassLoader() 也可能返回null 您唯一可以依賴的是系統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 (將ref傳遞給當前類)就可以了:

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服務器將是一個主要的例子),理解加載方案的性質和用法是值得的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM