Jede Klasse verwendet einen eigenen Klassenladeprogramm, um andere Klassen zu laden. Also , wenn ClassA.class
Referenzen ClassB.class
dann ClassB
muss sein auf dem Classpath des Classloader von ClassA
oder seinen Eltern.
Der Thread-Kontext-Klassenlader ist der aktuelle Klassenlader für den aktuellen Thread. Ein Objekt kann aus einer Klasse in erstellt ClassLoaderC
und dann an einen Thread übergeben werden, dessen Eigentümer es ist ClassLoaderD
. In diesem Fall muss das Objekt Thread.currentThread().getContextClassLoader()
direkt verwendet werden, wenn Ressourcen geladen werden sollen, die auf seinem eigenen Klassenladeprogramm nicht verfügbar sind.
ClassB
muss sich das auf dem Klassenpfad desClassA
Laders (oderClassA
der Eltern des Laders) befinden? Kann derClassA
Loader nicht überschrieben werdenloadClass()
, sodass er erfolgreich geladen werden kann,ClassB
auch wenn erClassB
sich nicht in seinem Klassenpfad befindet?ClassA.class
ReferenzenClassB.class
"?Dies beantwortet nicht die ursprüngliche Frage, aber da die Frage für jede
ContextClassLoader
Abfrage einen hohen Rang hat und verknüpft ist , halte ich es für wichtig, die zugehörige Frage zu beantworten, wann der Kontextklassenlader verwendet werden sollte. Kurze Antwort: Verwenden Sie niemals den Kontextklassenlader ! Stellen Sie es jedoch auf ein,getClass().getClassLoader()
wenn Sie eine Methode aufrufen müssen, bei der einClassLoader
Parameter fehlt .Wenn Code aus einer Klasse zum Laden einer anderen Klasse auffordert, ist der richtige Klassenlader derselbe Klassenlader wie die aufrufende Klasse (dh
getClass().getClassLoader()
). Auf diese Weise funktionieren die Dinge in 99,9% der Fälle, da die JVM dies selbst tut, wenn Sie zum ersten Mal eine Instanz einer neuen Klasse erstellen, eine statische Methode aufrufen oder auf ein statisches Feld zugreifen.Wenn Sie eine Klasse mithilfe von Reflection erstellen möchten (z. B. beim Deserialisieren oder Laden einer konfigurierbaren benannten Klasse), sollte die Bibliothek, die die Reflektion ausführt, die Anwendung immer fragen, welchen Klassenlader sie verwenden soll, indem sie den
ClassLoader
als Parameter von der Anwendung empfängt . Die Anwendung (die alle Klassen kennt, die erstellt werden müssen) sollte sie bestehengetClass().getClassLoader()
.Jede andere Möglichkeit, einen Klassenlader zu erhalten, ist falsch. Wenn eine Bibliothek verwendet Hacks wie
Thread.getContextClassLoader()
,sun.misc.VM.latestUserDefinedLoader()
odersun.reflect.Reflection.getCallerClass()
es ist ein durch einen Mangel in der API verursacht Fehler. GrundsätzlichThread.getContextClassLoader()
existiert nur, weil derjenige, der dieObjectInputStream
API entworfen hat, vergessen hat, denClassLoader
als Parameter zu akzeptieren , und dieser Fehler die Java-Community bis heute verfolgt hat.Das heißt, viele, viele JDK-Klassen verwenden einen der wenigen Hacks, um einen zu verwendenden Klassenlader zu erraten. Einige verwenden das
ContextClassLoader
(was fehlschlägt, wenn Sie verschiedene Apps in einem gemeinsam genutzten Thread-Pool ausführen oder wenn Sie das verlassenContextClassLoader null
), andere gehen den Stapel entlang (was fehlschlägt, wenn der direkte Aufrufer der Klasse selbst eine Bibliothek ist), andere verwenden den Systemklassenlader (was in Ordnung ist, solange dokumentiert ist, dass nur Klassen imCLASSPATH
) oder Bootstrap-Klassenladeprogramm verwendet werden, und einige verwenden eine unvorhersehbare Kombination der oben genannten Techniken (was die Dinge nur verwirrender macht). Dies hat zu viel Weinen und Zähneknirschen geführt.Versuchen Sie bei Verwendung einer solchen API zunächst, eine Überladung der Methode zu finden, die den Klassenlader als Parameter akzeptiert . Wenn es keine sinnvolle Methode gibt, versuchen Sie, die
ContextClassLoader
vor dem API-Aufruf festzulegen (und danach zurückzusetzen):quelle
Auf javaworld.com gibt es einen Artikel, der den Unterschied erklärt => Welchen ClassLoader sollten Sie verwenden?
(1)
(2) aus derselben Quelle:
quelle
bootstrap
Klassenlader, der als Kontextklassenlader festgelegt wird, sondern dersystem
untergeordnete Klassenpfadklassenlader, mit demThread
der eingerichtet wird. DieJNDI
Klassen stellen dann sicher, dass sieThread.currentThread().getContextClassLoader()
zum Laden der im Klassenpfad verfügbaren JNDI-Implementierungsklassen verwendet werden.Zusätzlich zur Antwort von @David Roussel können Klassen von mehreren Klassenladeprogrammen geladen werden.
Lassen Sie uns verstehen, wie Class Loader funktioniert.
Von javin paul blog in javarevisited:
ClassLoader
folgt drei Prinzipien.Delegationsprinzip
Bootstrap ClassLoader ist für das Laden von Standard-JDK-Klassendateien aus rt.jar verantwortlich und übergeordnet zu allen Klassenladeprogrammen in Java. Der Bootstrap-Klassenlader hat keine Eltern.
Die Erweiterung ClassLoader delegiert die Klassenladeanforderung an das übergeordnete Bootstrap und lädt, falls dies nicht erfolgreich ist, die Klasse aus dem Verzeichnis jre / lib / ext oder einem anderen Verzeichnis, auf das die Systemeigenschaft java.ext.dirs verweist
Der System- oder Anwendungsklassenlader ist für das Laden anwendungsspezifischer Klassen aus der Umgebungsvariablen CLASSPATH, der Befehlszeilenoption -classpath oder -cp sowie dem Klassenpfadattribut der Manifestdatei in JAR verantwortlich.
Application Class Loader ist ein untergeordnetes Element von Extension ClassLoader und wird von der
sun.misc.Launcher$AppClassLoader
Klasse implementiert .ANMERKUNG: Mit Ausnahme des Bootstrap-Klassenladeprogramms , das hauptsächlich in C in der Muttersprache implementiert ist, werden alle Java-Klassenladeprogramme mit implementiert
java.lang.ClassLoader
.Sichtbarkeitsprinzip
Prinzip der Einzigartigkeit
quelle