Vorwort
Jeder sollte wissen, dass das JVM beim Start eines Java -Projekts die Hauptmethode findet und die Klassendatei und die Klassendatei in das referenzierte JAR -Paket gemäß den Aufrufen zwischen den Objekten (die Schritte werden in Lade, Überprüfung, Vorbereitung, Analyse, Initialisierung, Verwendung und Entladen) geladen werden. Der Methodenbereich öffnet den Speicher, um die Laufzeitdatenstruktur der Klasse (einschließlich statischer Variablen, statische Methoden, konstante Pools, Klassenstrukturen usw.) zu speichern. Gleichzeitig wird das entsprechende Klassenobjekt im Heap generiert, um auf die entsprechende Klassen -Laufzeit -Datenstruktur im Methodenbereich zu verweisen.
Um im einfachsten Satz zusammenzufassen, lautet der Prozess des Klassenladens, dass das JVM die Klassen -Bytecode -Datei über IO -Streams basierend auf dem Pfad der erforderlichen Klassendatei liest und sie durch eine Reihe von Parsen- und Initialisierungsschritten in den Speicher in den Speicher einfließt. Klassenlader in Java gehören: BootstrapClassloader (obere Ebene), Extclassloader, AppClassloader und benutzerdefinierter Klassenloader (untere Ebene). Für verschiedene Arten von JAR -Paketen (oder Klassendateien) hat JVM verschiedene Arten von Klassenladern zum Laden.
Die entsprechende Beziehung ist wie folgt:
Der BootstrapClassloader wird verwendet, um die für JVM -Ausführungen erforderlichen Klassen zu laden:
JAVA_HOME/jre/lib/resources.jar: JAVA_HOME/jre/lib/rt.jar: JAVA_HOME/jre/lib/sunrasign.jar: JAVA_HOME/jre/lib/jsse.jar: JAVA_HOME/jre/lib/jce.jar: JAVA_HOME/jre/lib/charsets.jar: Java_home/jre/lib/jfr.jar: java_home/jre/lib/classes
Extclassloader wird verwendet, um Erweiterungsklassen zu laden:
.
AppClassloader wird verwendet, um die Klassen unter ClassPath und Klassen, auf die im JAR -Paket in unserem Projekt verwiesen wurde, zu laden.
Die gesamte Klassenbelastung wird durch einen Mechanismus geladen, der als Elterndelegation bezeichnet wird.
Beispielsweise wird eine Klasse vom Lader mit niedrigster Ebene (benutzerdefinierter Klassenloader) geladen. Dieser Loader ruft zunächst den vorherigen Level Loader (AppClassloader) zum Laden auf, und der AppClassloader wird weiterhin an die obere Ebene (Extclassloader) zum Laden übergeben, bis der Bootstrap -Classloader ist. Wenn der von BootstrapClassloader geladene Klassenpfad diese Klasse nicht finden kann, wird er an den Loader (Extclassloader) der nächsten Schicht zum Laden übergeben. Wenn diese Klasse nicht gefunden werden kann, wird sie weiterhin an die nächste Ebene (AppClassloader) zum Laden übergeben. Wenn der benutzerdefinierte Klassenloader diese Klasse nicht finden kann, werfen das Programm einen ClassNotFoundError.
Der gesamte Ladevorgang wird wie folgt angezeigt:
(Das Bild wird zitiert: https://www.cnblogs.com/xing901022/p/4574961.html)
Die Quellcodeverfolgung der Klassenladequelle ist wie folgt (der Quellcode wurde hier angemessen vereinfacht). Leser können auf den Quellcode klicken, um anzuzeigen:
Paket java.lang.classloader; importieren ...... geschützte Klasse <?> LoadClass (String -Name, boolean Resolve) löst ClassNotFoundException {synchronized (GetClassLoadingLock (Name)) {// Erstens in der virtuellen Maschinenspeicher finden, ob diese Klasse geladen wurde ... Der Hauptproblem mit Klassencache Lies!! ! ! Klasse <?> C = findloadedClass (Name); if (c == null) {long t0 = system.nanotime (); Versuchen Sie {if (parent! = null) {// Die vorherige Laderlader laden zuerst c = parent.loadClass (Name, false); } else {c = findbootstrapCassOrnull (name); }} catch (classNotFoundException e) {// classNotFoundException, wenn die Klasse nicht gefunden wird // aus der Nicht-Null-Elternklassen-Loader} if (c == null) {// Kalender die von diesem Loader implementierte FindClass-Methode, um c = findCass (Name) implementiert zu werden; }} if (Resolve) {ResolVeclass (c); } return c; }}Sie können den Prozess des übergeordneten Delegationsmechanismus im Quellcode voll und ganz schätzen, und die drei wichtigsten Code -Sätze wurden gekennzeichnet:
Wenn der Benutzer einen benutzerdefinierten Loader benötigt und die Klassendatei des angegebenen Pfades lädt, muss er den Klassenloader erben und die Methode für FindClass (String -Name) implementieren. Als Beispiel:
Paket com.linuxidc.utils; import Java.io.BytearrayoutputStream; Import Java.io.FileInputStream; Import Java.io.ioException; Import Java.io.inputStream; öffentliche Klasse serviceClassloader erweitert den Classloader {private String ClassPath; public serviceClassloader (String classPath) {this.classPath = classPath; } /*** Schreiben Sie die FindClass -Methode der übergeordneten Klasse neu. Die LoadClass der übergeordneten Klasse nennt diese Methode */ @Override Protected Class <?> FindClass (String -Name) löst classNotFoundException {class <?> C = null aus; byte [] classData = getClassData (Name); if (classData! } else {werfen neuer classNotFoundException (); } return c; } // Lesen Sie die Klassendatei über den IO -Stream und konvertieren sie in ein Byte -Array privat Byte [] getClassData (String -Name) {String path = classPath + "/" + name.replace ('.', '/') + ".Class"; InputStream isTream = null; BytearrayoutputStream bytearrayoutputStream = new bytearrayoutputStream (); try {isTream = new FileInputStream (Pfad); byte [] buffer = neues byte [1024]; int temp = 0; while ((temp = iStream.read (puffer))! } if (bytearrayoutputStream! = null) {return bytearrayoutputStream.tobytearray (); }} catch (Ausnahme e) {e.printstacktrace (); } endlich {try {if (iStream! = null) {isTream.close (); }} catch (ioException e) {e.printstacktrace (); } try {if (bytearrayoutputStream! = null) {bytearrayoutputStream.CLOSE (); }} catch (ioException e) {e.printstacktrace (); }} return null; }}Der Code für die Verwendung des Klassenladers lautet wie folgt:
ServiceClassloader serviceClassloader = new serviceClassloader ("c:/myclass"); czklass <?> C = serviceClassloader.loadClass ("com.linuxidc.service.myclass");Wenn Sie das gleiche ServicEClassloader -Objekt verwenden, um dieselbe Klassendatei mehrmals zu laden, ist das Klassenobjekt nach jeder Last gleich! Wenn jedoch ein neuer verschiedener benutzerdefinierter Klassenloader dieselbe Klassendatei lädt, wird jedes Mal ein anderes Klassenobjekt zurückgegeben.
HINWEIS: Die Klassendatei, die Sie laden möchten, kann nicht in das Klassenpath -Verzeichnis und alle Unterverzeichnisse platziert werden. Andernfalls wird sie zuerst vom AppClassloader geladen (dies liegt daran, dass das Laden der Klasse den übergeordneten Delegationsmechanismus annimmt und der AppClassloader alle Klassendateien unter dem Klassenpath laden kann). Jedes Mal wird derselbe AppClassloader geladen, sodass Klassenprobleme vorhanden sind.
Dies löst das Problem der direkten Verwendung von Reflexion, wenn die JVM -Klasse lädt.
Zusammenfassen
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, dass der Inhalt dieses Artikels einen gewissen Referenzwert für das Studium oder die Arbeit eines jeden hat. Wenn Sie Fragen haben, können Sie eine Nachricht zur Kommunikation überlassen. Vielen Dank für Ihre Unterstützung bei Wulin.com.