Questo non risponde alla domanda originale, ma poiché la domanda è classificata e collegata per qualsiasi ContextClassLoaderquery, penso che sia importante rispondere alla domanda correlata su quando utilizzare il caricatore di classi di contesto. Risposta breve: non usare mai il caricatore di classi di contesto ! Ma impostalo su getClass().getClassLoader()quando devi chiamare un metodo in cui manca un ClassLoaderparametro.
Quando il codice di una classe chiede di caricare un'altra classe, il caricatore di classi corretto da utilizzare è lo stesso caricatore di classi della classe chiamante (ovvero, getClass().getClassLoader()). Questo è il modo in cui le cose funzionano il 99,9% delle volte perché è ciò che la JVM fa da sola la prima volta che costruisci un'istanza di una nuova classe, invoca un metodo statico o accedi a un campo statico.
Quando si desidera creare una classe utilizzando la riflessione (come quando si deserializza o si carica una classe denominata configurabile), la libreria che esegue la riflessione dovrebbe sempre chiedere all'applicazione quale caricatore di classe utilizzare, ricevendo ClassLoadercome parametro dall'applicazione. L'applicazione (che conosce tutte le classi che devono essere costruite) dovrebbe passarla getClass().getClassLoader().
Qualsiasi altro modo per ottenere un caricatore di classi non è corretto. Se una libreria utilizza hack come Thread.getContextClassLoader(), sun.misc.VM.latestUserDefinedLoader()o sun.reflect.Reflection.getCallerClass()è un bug causato da un difetto nell'API. Fondamentalmente, Thread.getContextClassLoader()esiste solo perché chiunque abbia progettato l' ObjectInputStreamAPI ha dimenticato di accettarlo ClassLoadercome parametro e questo errore ha perseguitato la comunità Java fino ad oggi.
Detto questo, molte molte classi JDK usano uno dei pochi hack per indovinare un caricatore di classi da usare. Alcuni usano il ContextClassLoader(che fallisce quando si eseguono app diverse su un pool di thread condiviso o quando si lascia il ContextClassLoader null), altri camminano nello stack (che fallisce quando il chiamante diretto della classe è esso stesso una libreria), altri usano il caricatore di classi di sistema (il che va bene, purché sia documentato l'uso solo delle classi nel CLASSPATH) o caricatore di classi bootstrap, e alcuni usano una combinazione imprevedibile delle tecniche di cui sopra (il che rende le cose più confuse). Ciò ha provocato molto pianto e digrignamento dei denti.
Quando si utilizza un'API di questo tipo, provare innanzitutto a trovare un sovraccarico del metodo che accetta il programma di caricamento classi come parametro . Se non esiste un metodo ragionevole, prova a impostare ContextClassLoaderprima della chiamata API (e reimpostarla in seguito):
ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
// call some API that uses reflection without taking ClassLoader param
} finally {
Thread.currentThread().setContextClassLoader(originalClassLoader);
}
ClassBdeve essere sul percorso di classe delClassAcaricatore (oClassAdei genitori del caricatore)? Non è possibileClassAeseguire l'override del caricatoreloadClass(), in modo che possa essere caricato correttamenteClassBanche quandoClassBnon si trova sul suo percorso di classe?