Bei der Entwicklung von Java das Grundwissen, mit dem Sie im Klassenloadermechanismus vertraut sein müssen. Dieser Artikel fasst kurz den Java Classloader -Mechanismus zusammen. Da verschiedene JVM -Implementierungen unterschiedlich sind, beschränkt sich der in diesem Artikel beschriebene Inhalt auf Hotspot -JVM.
Dieser Artikel beginnt mit den vier Aspekten von Classloader, dem von JDK bereitgestellten übergeordneten Delegationsmodell, dem Anpassen von Klassenloader und Szenarien, die den übergeordneten Delegationsmechanismus in Java brechen.
JDK Standard Classloader
JDK bietet standardmäßig die folgenden Klassenloader an
Bootstrp Loader
Der Bootstrp Loader ist in C ++ - Sprache geschrieben. Es wird initialisiert, nachdem die virtuelle Java -Maschine gestartet wurde. Es ist hauptsächlich dafür verantwortlich, den von dem %java_home %/jre/lib, -xbootClassPath und den Klassen in %Java_Home %/jre/Klassen angegebenen Pfad zu laden.
Extaderlader
Der BootStrp Loader lädt den Extclassloader und legt den übergeordneten Loader des Extclassloaders auf BootStrp Loader fest. EXTCASSCASSLOADER ist in Java geschrieben, insbesondere in sun.misc.launcher $ extclassloader. Der Extclassloader lädt hauptsächlich %Java_Home %/JRE/lib/ext, alle Klassenverzeichnisse unter diesem Pfad und Klassenbibliotheken auf dem von der Java.ext.dirs -Systemvariablen angegebenen Pfad.
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. Die Implementierungsklasse ist sun.misc.launcher $ AppClassloader. Darüber hinaus wissen wir, dass es im Classloader eine Get -SystemClassloader -Methode gibt. Diese Methode gibt den AppClassloader.AppClassloader zurück, der hauptsächlich für das Laden des von ClassPath angegebenen Ortes oder JAR -Dokuments verantwortlich ist. Es ist auch der Standardklassenloader für Java -Programme.
Elterndelegationsmodell
Das Laden der Klassenlader in Java nimmt einen übergeordneten Delegiertenmechanismus an. Wenn Sie Klassen unter Verwendung eines übergeordneten Delegiertenmechanismus laden, werden die folgenden Schritte angewendet:
Derzeit prüft Classloader zuerst, ob diese Klasse aus der bereits geladenen Klasse geladen wurde. Wenn es geladen wurde, gibt es die ursprüngliche Klasse direkt zurück.
Jeder Klassenloader hat seinen eigenen Ladecache. Wenn eine Klasse geladen wird, wird sie in den Cache gesteckt und kann direkt zurückgegeben werden, wenn sie das nächste Mal geladen wird.
Wenn der Cache des Klassenloaders nicht gefunden wird, wird der übergeordnete Klassenloader zum Laden delegiert. Der übergeordnete Klassenlader übernimmt die gleiche Strategie. Überprüfen Sie zuerst seinen eigenen Cache und delegieren Sie dann die übergeordnete Klasse der übergeordneten Klasse, um bis zum BootStrp -Klasseloader zu laden.
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 Klassenloader erhöht. Wie oben erwähnt, haben die Klassenbibliotheken, die von unserem JDK Binsheng bereitgestellt wurden, wie HashMap, LinkedList usw., nachdem diese Klassen vom BootStrp -Klassenlader geladen wurden, unabhängig davon, wie viele Klassenlader in Ihrem Programm in Ihrem Programm enthalten sind, können diese Klassen tatsächlich geteilt werden, wodurch Verwirrung verursacht wird, die durch verschiedene Klassenlader geladen werden, die unterschiedliche Klassen desselben Namens derselben Namensklassen laden.
So stellen Sie den Klassenloader an
Zusätzlich zu dem oben erwähnten Klassenloader ermöglicht Java auch Anwendungen, den Klassenloader anzupassen. Wenn Sie den Klassenloader anpassen möchten, müssen wir ihn implementieren, indem wir java.lang.classloader erben. Schauen wir uns als nächstes mehrere wichtige Methoden an, auf die wir beim Anpassen des Klassenloaders achten müssen:
1. LoadClass -Methode
Lastklasse -Methode deklarieren
öffentliche Klasse <?> LoadClass (String -Name) löst ClassNotFoundException aus
Das obige ist die Prototypdeklaration der Lastklasse -Methode. Die Implementierung des oben genannten übergeordneten Delegationsmechanismus wird in dieser Methode tatsächlich implementiert. 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 überprüfen, ob die Klasse bereits geladen wurde. Der Loader wird angegeben, der übergeordnete Loader wird zum Laden delegiert. } else {c = findbootstrapClass0 (name); // Wenn es keinen übergeordneten Klassenlader gibt, delegieren Sie dann den Bootstrap -Loader zum Laden}} catch (classNotFoundException e) {// Wenn immer noch nicht gefunden, rufen Sie die Fundklasse in der Reihenfolge auf //, um die Klasse zu finden. C = FindClass (Name); // Wenn die übergeordnete Ladeklasse nicht geladen ist, wird sie über seine eigene FindClass geladen. }} 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. Lassen Sie uns als nächstes darüber sprechen, ob diese Methode schlecht ist.
2.FindClass
Wir überprüfen den Quellcode von Java.lang.Classloader und stellen fest, 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. Sie können von der Festplatte lesen oder den Byte -Stream von Klassendateien aus dem Netzwerk abrufen. Nachdem Sie die Klassen binäre erhalten haben, können Sie es für ein weiteres Laden an eindeutig übergeben. 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 wird, was bedeutet, dass diese Methode nicht überschrieben werden kann. Tatsächlich ist dies auch der einzige Eintrag, der uns von JVM hinterlassen hat. Durch diesen eindeutigen Eintrag stellt JVM sicher, dass die Klassendatei der Definition der in der Spezifikation Java Virtual Machine angegebenen Klasse entsprechen muss. 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 gebrochen 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 für Klassen, die mit Java beginnen.*Die Implementierung von JVM hat sichergestellt, dass sie von Bootstrp geladen werden muss.
Szenarien, die nicht dem "übergeordneten Delegationsmechanismus" folgen "
In dem obigen erwähnte, dass der übergeordnete Delegationsmechanismus hauptsächlich das Interaktionsproblem von Klassen, die zwischen verschiedenen Klassenloadern geladen sind, realisieren. Die Klassen, die von jedem geteilt werden, werden dem übergeordneten Loader zum Laden übergeben. In Java gibt es jedoch tatsächlich eine Situation, in der Klassen, die von der übergeordneten Klassenlader geladen wurden, Klassen verwenden müssen, die vom Kinderloa geladen wurden. Lassen Sie uns über das Auftreten dieser Situation sprechen.
In Java gibt es einen SPI -Standard (ServiceProviderinterface), 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 JAR -Paket des Fahrers wird in den Klassenpfad unserer Anwendung selbst platziert. Die API von JDBC selbst ist Teil des von JDK bereitgestellten JDK und wurde von Bootstrp geladen. Wie lade ich die Implementierungsklassen, die von Herstellern von Drittanbietern bereitgestellt werden? Java führt das Konzept des Ladens der Thread -Kontextklasse ein. Der Thread Class Loader erbt standardmäßig aus dem übergeordneten Thread. Wenn es nicht angegeben ist, ist der Standard der Systemklasse Loader (AppClassloader). Auf diese Weise kann ein Dritter-Treiber geladen werden, er kann durch den Kontextklassenlader des Threads geladen werden.
Um flexiblere OSGI und einige JavaAppServers flexiblere Klassenlader zu implementieren, bricht es außerdem den übergeordneten Delegationsmechanismus.
Zusammenfassen
Das obige ist der gesamte Inhalt dieses Artikels über die Codeanalyse der Nutzung und Verwendung des Java Classloader -Mechanismus. Ich hoffe, es wird für alle hilfreich sein. Interessierte Freunde können weiterhin auf andere verwandte Themen auf dieser Website verweisen. Wenn es Mängel gibt, hinterlassen Sie bitte eine Nachricht, um darauf hinzuweisen. Vielen Dank an Freunde für Ihre Unterstützung für diese Seite!