Es gibt zwei Arten von Klassenladungen in Java, einer ist benutzerdefiniert und der andere ist der in JVM integrierte Bootstrap-Klassenlader.
In JVM sind drei Arten von Klassenladern integriert, nämlich Bootstrap -Klasseloader, Erweiterungsklassenloader (d. H. Extclassloader) und System Classloader (d. H. AppClassloader).
Ich werde nicht über die Elterndelegation sprechen, wenn JVM geladen ist. Es gibt viele Artikel über Javaeye, die vorgestellt werden ...
Sie können sich ihre Konstruktoren separat ansehen, wo der Bootstrap -Klassenloader in c geschrieben ist.
java.lang.classloader
Protected Classloader (Classloader) {SecurityManager Security = System.getSecurityManager (); true; initialisiert = wahr;
Dieser Konstruktor hat zwei Parameter und keinen Konstruktor. Der Konstruktor mit Parametern übergibt den übergeordneten Loader dieses Klassenladers, während der Konstruktor ohne Parameter den von GetSystemClassloader () zurückgegebenen Klassenlader als seinen eigenen übergeordneten Loader behandelt
public statische Klassenloader getSystemClassloader () {// Der zurückgegebene Klassenlader wird initSystemClassloader () zugewiesen; ccl = getCallerClassloader (); if (! sclset) {if (scl! oops = null; // dem Wert wird scl = l.getClassloader () zugewiesen; .... ..................................................................................................................................................................................................................................................................................... Der übergeordnete Klassenloader hier ist SCL, der von L.GetClassloader (), getClassloader () erhalten wird und dann den Quellcode von Launcher ansehen:
private static Launcher Launcher = New Launcher ();
öffentlicher statischer Launcher Getlauncher () {Rückgabestarif; ); AppClassloader, das heißt, der GetsystemClassloader gibt AppClassLoader Loader = AppClassloader.getAppClassloader (extcl) zurück; Thread, um Verwirrung zu verhindern, die durch Klassenladungen in Multithreads verursacht werden (ich verstehe dies selbst, haha) // SetContextClassloader (lo aser) auch den Kontextklassenlader für den primären Thread festlegen. .............................................. ................................................................................................................................................................................................. ..............} / * * Gibt den Klassenlader zurück, mit dem die Hauptanwendung startet. Daraus erkennen wir, dass der übergeordnete Loader des AppClassloaders extclassloader ist und wie lautet der übergeordnete Loader des Extclassloaders? Schauen wir uns den Extclassloader -Konstruktor an:
public extclassloader (Datei [] Dirs) löst ioException {Super (getexturls (Dirs), null, fabrik) aus;Sein Elternlader ist leer, während seine übergeordnete Elternklasse Java.lang.Classloader ist.
Protected Synchronisierte Klasse <?> LoadClass (String -Name, boolean Resolve) löst ClassNotFoundException aus {// Überprüfen Sie zuerst, ob die Klasse bereits geladen wurde. ! ) {// found nicht gefunden, um die Klasse zu finden, um die Klasse zu finden.Hier soll FindbootstrapClass0 den Bootstrap Classloader, den Kernklassenloader, aufrufen, um die Klasse zu laden.
Schließlich können wir sehen, dass der von getsystemClassloader () zurückgegebene Klassenloader AppClassloader ist.
Java Classloader -Mechanismusanalyse
JDK Standard Classloader
JDK bietet standardmäßig die folgenden Klassenloader an
Bootstrp Loader
Der Bootstrp-Loader ist in C ++-Sprache geschrieben. JRE/Klassen.
Extaderlader
Der BootStrp -Loader lädt den Extclassloader und legt den übergeordneten Loader des Extclassloaders auf den Bootstrp -Loader fest. Dies alle Klassenverzeichnisse unter den Pfad- und Klassenbibliotheken im Pfad, das durch die Systemvariable von Java.ext.dirs angegeben ist.
AppClassloader
Nachdem der BootStrp Loader den Extclassloader geladen hat, wird der AppClassloader geladen und der übergeordnete Loader des AppClassloaders als Extclassloader angegeben. AppClassloader ist auch in Java geschrieben. Es handelt sich um ein JAR -Dokument, das auch der Standardklassenloader für Java -Programme ist.
Zusammenfassend kann die Beziehung zwischen ihnen in der folgenden Abbildung beschrieben werden:
Elterndelegationsmodell
Das Laden von Classloader in Java wird bei der Ladeklassen mit einem übergeordneten Delegiertenmechanismus einen übergeordneten Delegiertenmechanismus angewendet:
Derzeit prüft Classloader zuerst, ob diese Klasse aus der Klasse geladen wurde, wenn sie geladen wurde.
Jeder Klassenlader hat seinen eigenen Lade -Cache.
Wenn der Classloader -Cache nicht gefunden wird, wird der Lader der Elternklasse delegiert, um ihn zuerst zu laden. Weg zum BootStrp -Klassenloader.
Wenn nicht alle übergeordneten Klassenlader geladen werden, werden sie vom aktuellen Klassenlader geladen und in ihren eigenen Cache gesteckt, damit sie beim nächsten Mal direkt zurückgegeben werden können.
Apropos, Sie fragen sich vielleicht, warum Java einen solchen Delegationsmechanismus annimmt. Um dieses Problem zu verstehen, stellen wir einen anderen Konzept "Namespace" über Classloader ein, was bedeutet, dass Sie einen vollständig qualifizierten Namen der Klasse für die Bestimmung einer bestimmten Klasse benötigen und diesen Klassenloader laden müssen, um diese gemeinsam zu bestimmen. Das heißt, selbst wenn die voll qualifizierten Namen der beiden Klassen gleich sind, da verschiedene Klassenloader diese Klasse laden, ist es eine andere Klasse im JVM. Schauen wir uns nach dem Verständnis des Namespace das Delegate -Modell an. Nach der Übernahme des Delegiertenmodells werden die interaktiven Fähigkeiten verschiedener Klassenlader erhöht. Messen Sie Ihr Programm Es gibt so viele Klassenlader darin, sodass diese Klassen tatsächlich geteilt werden können, was Verwirrung vermeidet, die durch verschiedene Klassenlader verursacht werden, nachdem verschiedene Klassen gleicher Namen geladen werden.
So stellen Sie den Klassenloader an
Zusätzlich zu dem oben genannten Standard -Klassenloader ermöglicht Java die Anpassung des Klassenloaders. Wir müssen auf mehrere wichtige Methoden achten:
1. LoadClass -Methode
Lastklasse -Methode deklarieren
öffentliche Klasse <?> LoadClass (String -Name) löst ClassNotFoundException aus
Das obige ist die Prototyperklärung der Lastklasse -Methode. Schauen wir uns den Code dieser Methode an, um zu sehen, wie er die Elterndelegation implementiert.
LOADCASS -Methode Implementierung
öffentliche Klasse <?> LoadClass (String -Name) löst ClassNotFoundException {return LoadClass (Name, False);} ausAus dem obigen Punkt können wir sehen, dass die Lastklasse -Methode die Methode für die LoadClass (Name, False) aufruft. Schauen wir uns also die Implementierung einer anderen Lastklasse -Methode an.
Klasse LoadClass (String -Name, boolescher Auflösung)
Protected Synchronisierte Klasse <?> LoadClass (String -Name, Boolean Resolve) löst ClassNotFoundException aus {// Erstens prüfen, ob die Klasse bereits geladen wurde. = null) {try {if (parent! = null) {c = parent.loadClass (Name, false); } else {c = findbootstrapClass0 (name); // Wenn es keinen übergeordneten Klassenlader gibt, löschen Finden Sie die Klasse. }} if (Resolve) {ResolVeclass (c);} return c;}Im obigen Code habe ich Kommentare hinzugefügt, um klar zu sehen, wie der übergeordnete Delegationsmechanismus der LoadClass funktioniert. Eine Sache, die wir hier beachten müssen, ist, dass die öffentliche Klasse <?> LoadClass (String -Name) ClassNotFoundException nicht als endgültig markiert wird, was bedeutet, dass wir diese Methode überschreiben können, was bedeutet, dass der übergeordnete Delegationsmechanismus gebrochen werden kann. Darüber hinaus haben wir festgestellt, dass es oben eine FindClass -Methode gibt.
2.FindClass
Wir überprüfen den Quellcode von Java.lang.Classloader und finden, dass die Implementierung von FindClass wie folgt ist:
Protected Class <?> FindClass (String -Name) löst ClassNotFoundException {neue classNotFoundException (Name);} ausWir können sehen, dass die Standardimplementierung dieser Methode darin besteht, Ausnahmen direkt zu veröffentlichen. Tatsächlich bleibt diese Methode unserer Anwendung überlassen. Die spezifische Implementierung hängt von Ihrer Implementierungslogik ab. Beschreiben wir Definition später. OK, durch die obige Analyse können wir folgende Schlussfolgerungen ziehen:
Wenn wir unseren eigenen Klassenloader schreiben, müssen wir FundClass nur außer Kraft setzen, wenn wir dem übergeordneten Delegationsmechanismus folgen möchten.
3. Definition
Schauen wir uns zunächst den Quellcode definitiv an:
definitiv
Protected Final Class <?> DeclessEclass (String -Name, Byte [] b, int off, int len) löscht Classformaterror {return Decless (Name, B, Off, Len, NULL);};}Aus dem obigen Code können wir sehen, dass diese Methode als endgültig definiert ist, was bedeutet, dass diese Methode nicht überschrieben werden kann. Die Datei muss der Definition von Klassen entsprechen, die in der Spezifikation der Java Virtual Machine angegeben sind. Diese Methode ruft schließlich die native Methode auf, um das Laden der realen Klasse zu implementieren.
OK, denken wir durch die obige Beschreibung über die folgende Frage nach:
Wenn wir selbst eine Java.lang.String -Klasse geschrieben haben, können wir dann die Klasse ersetzen, die JDK selbst nennt?
Die Antwort ist nein. Wir können es nicht erreichen. Warum? Ich sehe viele Online -Erklärungen, dass der übergeordnete Delegationsmechanismus dieses Problem löst, aber es ist eigentlich nicht sehr genau. Da der übergeordnete Delegationsmechanismus unterbrochen werden kann, können Sie einen Klassenloader schreiben, um die von Ihnen geschriebene Java.lang.String -Klasse zu laden, aber Sie werden feststellen, dass er nicht erfolgreich geladen wird, insbesondere weil er für die Klassen beginnt, beginnend mit Java.*,,,. JVM Die Implementierung hat dafür gesorgt, dass sie von BootStrp geladen werden muss.
Szenarien, die nicht dem "übergeordneten Delegationsmechanismus" folgen "
In dem oben genannten Mechanismus der übergeordneten Delegation wird hauptsächlich das Interaktionsproblem von Klassen, die zwischen verschiedenen Klassenladern geladen sind, erkennen. Elternklassenlader in Java. Lassen Sie uns über das Auftreten dieser Situation sprechen.
In Java gibt es einen SPI -Standard (Service Provider Interface), der SPI -Bibliotheken wie JDBC, JNDI usw. verwendet. Wir alle wissen, dass JDBC Treiber benötigt, die von Dritten zur Verfügung gestellt werden, und das Treiber -JAR -Paket ist in unserer Anwendung selbst platziert. Der ClassPath und die API von JDBC sind Teil der JDK-Bestimmung und wurde von BootStrp geladen. Java führt das Ladekonzept des Thread-Kontextklassen ein. Treiber, es ist in Ordnung, den Kontextklassenlader des Threads durch das Laden zu laden.
Um flexiblere OSGI und einige Java -App -Server flexiblerer Klassenlader zu implementieren, wird außerdem der übergeordnete Mechanismus der übergeordneten Delegationsmechanismus unterbrochen.