- Vorwort -Verstehen Sie den Klassenlademechanismus von Apache Tomcat? Dieser Artikel beginnt mit den zugrunde liegenden Prinzipien und stellt ausführlich den Quellcode, die Mechanismen und die Lösungen dar, die beim Laden von Tomcat-Klassen eine Rolle spielen. So lernen Sie die Grundlagen des Ladens von Tomcat-Klassen gründlich! - JVM-Klassenlader -1. JVM-KlassenladerWenn wir über den Tomcat-Klassenlader sprechen, müssen wir kurz über den JVM-Klassenlader sprechen, wie in der folgenden Abbildung dargestellt:
Das Funktionsprinzip dieser Klassenlader ist dasselbe. Der Unterschied besteht darin, dass ihre Ladepfade unterschiedlich sind, d. h. die von der Methode findClass durchsuchten Pfade sind unterschiedlich. Der übergeordnete Delegationsmechanismus soll sicherstellen, dass eine Java-Klasse in der JVM eindeutig ist. Wenn Sie versehentlich eine Klasse mit demselben Namen wie eine JRE-Kernklasse schreiben, z. B. die Object-Klasse, kann der übergeordnete Delegationsmechanismus sicherstellen, dass die Object-Klasse in der JRE geladen wird und nicht die von Ihnen geschriebene Object-Klasse. Dies liegt daran, dass AppClassLoader beim Laden Ihrer Object-Klasse das Laden an ExtClassLoader delegiert und ExtClassLoader wiederum an BootstrapClassLoader delegiert. BootstrapClassLoader stellt fest, dass es die Object-Klasse bereits geladen hat und kehrt direkt zurück, ohne die von Ihnen geschriebene Object-Klasse zu laden. Bitte beachten Sie hierbei, dass die Eltern-Kind-Beziehung von Klassenladern nicht durch Vererbung realisiert wird. Beispielsweise ist AppClassLoader keine Unterklasse von ExtClassLoader, aber die übergeordnete Mitgliedsvariable von AppClassLoader zeigt auf das ExtClassLoader-Objekt. Wenn Sie den Klassenlader anpassen möchten, erben Sie nicht AppClassLoader, sondern die abstrakte Klasse ClassLoader und schreiben Sie dann die Methoden findClass und loadClass neu. Tomcat implementiert seine eigene Klassenladelogik über einen benutzerdefinierten Klassenlader. Ich weiß nicht, ob Sie bemerkt haben, dass Sie die loadClass-Methode neu schreiben müssen, wenn Sie den übergeordneten Delegierungsmechanismus unterbrechen möchten, da die Standardimplementierung von loadClass der übergeordnete Delegierungsmechanismus ist. 2. Quellcode des Klassenladersöffentliche abstrakte Klasse ClassLoader { // Jeder Klassenlader hat einen übergeordneten Loader private final ClassLoader parent; öffentliche Klasse<?> loadClass(String name) löst ClassNotFoundException { aus gibt loadClass(Name, false) zurück; } geschützte Klasse<?> loadClass(String-Name, Boolesche Auflösung) löst ClassNotFoundException aus { // Überprüfen Sie zunächst, ob die Klasse bereits geladen wurde Klasse<?> c = findLoadedClass(Name); // Wenn nicht geladen if (c == null) { wenn (Elternteil != null) { // Delegieren Sie das Laden zunächst an den übergeordneten Loader. Beachten Sie, dass dies ein rekursiver Aufruf ist. c = parent.loadClass(name, false); } anders { // Wenn der übergeordnete Loader leer ist, prüfen Sie, ob der Bootstrap Loader geladen wurde c = findBootstrapClassOrNull(name); } // Wenn das Laden des übergeordneten Loaders fehlschlägt, rufe seine eigene findClass zum Laden auf, if (c == null) { c = Klasse finden(Name); } } Rückkehr c; } } //Die Methode findClass im ClassLoader muss von der Unterklasse überschrieben werden. Der folgende Code ist der entsprechende Code protected Class<?> findClass(String name){ //1. Suchen Sie gemäß dem übergebenen Klassennamen nach der Klassendatei in einem bestimmten Verzeichnis und lesen Sie die .class-Datei in den Speicher ein ... //2. Rufen Sie defineClass auf, um das Byte-Array in ein Class-Objekt umzuwandeln return defineClass(buf, off, len); } // Analysieren Sie das Bytecode-Array in ein Class-Objekt und implementieren Sie es mit nativen Methoden protected final Class<?> defineClass(byte[] b, int off, int len){ } } Unser benutzerdefinierter Klassenlader muss die loadClass-Methode des ClassLoaders neu schreiben. - Tomcats Klassenlademechanismus - 1. Eigenschaften des LademechanismusIsolierung: Web-Anwendungsbibliotheken sind voneinander isoliert, um zu verhindern, dass abhängige Bibliotheken oder Anwendungspakete sich gegenseitig beeinflussen. Stellen Sie sich vor, wir haben zwei Webanwendungen, von denen eine Spring 2.5 und die andere Spring 4.0 verwendet, und der Anwendungsserver verwendet zum Laden einen Klassenlader. Dann kann die Webanwendung aufgrund des Überschreibens des Jar-Pakets nicht erfolgreich gestartet werden. Flexibilität: Da die Klassenlader zwischen Webanwendungen unabhängig voneinander sind, können wir nur eine Webanwendung erneut bereitstellen, und der Klassenlader der Webanwendung wird neu erstellt, ohne dass dies Auswirkungen auf andere Webanwendungen hat. Wenn Sie einen Klassenlader verwenden, ist dies offensichtlich nicht möglich, da bei nur einem Klassenlader die Abhängigkeiten zwischen den Klassen unorganisiert sind und es unmöglich ist, die Klassen einer Webanwendung vollständig zu entfernen. Performance: Da jede Web-Anwendung über einen Klassenlader verfügt, sucht die Web-Anwendung beim Laden von Klassen nicht nach Jar-Paketen, die in anderen Web-Anwendungen enthalten sind. Die Performance ist natürlich höher, als wenn der Anwendungsserver nur einen Klassenlader hätte. 2. Tomcat-Klassenladelösung
Tomcat 8.5 hat den strikten übergeordneten Delegierungsmechanismus standardmäßig geändert:
3. Analysieren Sie den Ladevorgang des AnwendungsklassenladersDer Anwendungsklassenlader ist WebappClassLoader und seine Ladeklasse befindet sich in seiner übergeordneten Klasse WebappClassLoaderBase. öffentliche Klasse<?> loadClass(Stringname, Boolesche Auflösung) wirft ClassNotFoundException { synchronisiert (getClassLoadingLock(name)) { wenn (log.isDebugEnabled()) log.debug("loadClass(" + name + ", " + resolve + ")"); Klasse<?> clazz = null; // Zugriff auf gestoppten Klassenlader protokollieren : Überprüfen Sie den Status des Klassenladevorgangs. //Laden Sie die Klasse aus dem lokalen Cache des aktuellen ClassLoaders und geben Sie sie zurück, wenn sie gefunden wurde: clazz = findLoadedClass0(name); if (clazz != null) { wenn (log.isDebugEnabled()) log.debug("Klasse aus Cache zurückgeben"); wenn (auflösen) Klasse auflösen(clazz); Rückgabeklazz; } // Wenn kein lokaler Cache vorhanden ist, rufen Sie die Methode findLoadedClass von ClassLoader auf, um zu prüfen, ob die JVM diese Klasse geladen hat. Wenn ja, kehren Sie direkt zurück. clazz = findeLoadedClass(name); if (clazz != null) { wenn (log.isDebugEnabled()) log.debug("Klasse aus Cache zurückgeben"); wenn (auflösen) Klasse auflösen(clazz); Rückgabeklazz; } Zeichenfolge „Ressourcenname“ = „binaryNameToPath“ (Name, „false“). // Zu diesem Zeitpunkt ist javaseClassLoader der Erweiterungsklassenlader, und der Erweiterungsklassenlader wird javaseClassLoader zugewiesen. Ich habe versucht, den ClassLoader zu starten, aber ich habe ihn nicht gestartet. Boolescher Wert tryLoadingFromJavaseLoader; versuchen { ..... //Wenn es mit getResource abgerufen werden kann //Wenn es mit getResource des Erweiterungsklassenladers abgerufen werden kann, beweist dies, dass es vom Erweiterungsklassenlader geladen werden kann. Als nächstes veranlassen Sie das Laden des Erweiterungsklassenladers, wenn (tryLoadingFromJavaseLoader) { versuchen { //Verwenden Sie zum Laden den erweiterten Klassenlader clazz = javaseLoader.loadClass(name); if (clazz != null) { wenn (auflösen) Klasse auflösen(clazz); Rückgabeklazz; } } Fang (ClassNotFoundException e) { // Ignorieren } } // (0.5) Berechtigung zum Zugriff auf diese Klasse bei Verwendung eines SecurityManagers if (securityManager != null) { int i = name.letzterIndexVon('.'); wenn (i >= 0) { versuchen { securityManager.checkPackageAccess(name.substring(0,i)); } Fang (Sicherheitsausnahme se) { String-Fehler = "Sicherheitsverletzung, Versuch der Verwendung von " + "Eingeschränkte Klasse: " + Name; log.info(Fehler, se); wirf eine neue ClassNotFoundException (Fehler, se); } } } boolean delegateLoad = Delegierter || Filter (Name, wahr); // (1) Delegieren an unser übergeordnetes Element, falls gewünscht //Wenn wahr, verwende den übergeordneten Klassenlader zum Laden, wenn (delegateLoad) { wenn (log.isDebugEnabled()) log.debug("Delegieren an übergeordneten classloader1 " + parent); versuchen { clazz = Klasse.forName(Name, falsch, übergeordnetes Element); if (clazz != null) { wenn (log.isDebugEnabled()) log.debug("Klasse vom übergeordneten Element wird geladen"); wenn (auflösen) Klasse auflösen(clazz); Rückgabeklazz; } } Fang (ClassNotFoundException e) { // Ignorieren } } // (2) Suche in lokalen Repositorien wenn (log.isDebugEnabled()) log.debug("Lokale Repositories durchsuchen"); versuchen { // Lokal laden clazz = findClass(name); if (clazz != null) { wenn (log.isDebugEnabled()) log.debug("Klasse aus lokalem Repository laden"); wenn (auflösen) Klasse auflösen(clazz); Rückgabeklazz; } } Fang (ClassNotFoundException e) { // Ignorieren } // (3) Bedingungslose Delegierung an übergeordnetes Element //Es wurde noch nicht geladen. Versuchen Sie, es mit dem übergeordneten Klassenlader erneut zu laden, if (!delegateLoad) { wenn (log.isDebugEnabled()) log.debug("Delegieren an übergeordneten Klassenlader am Ende: " + übergeordneter Klassenlader); versuchen { clazz = Klasse.forName(Name, falsch, übergeordnetes Element); if (clazz != null) { wenn (log.isDebugEnabled()) log.debug("Klasse vom übergeordneten Element wird geladen"); wenn (auflösen) Klasse auflösen(clazz); Rückgabeklazz; } } Fang (ClassNotFoundException e) { // Ignorieren } } } wirf eine neue ClassNotFoundException(Name); } Hinweis: In der 37. Zeile des englischen Kommentars ist vermerkt, dass der Systemklassenlader erhalten wurde. Beim Debuggen stellen wir jedoch fest, dass es sich um einen Erweiterungsklassenlader handelt. In der Praxis können wir daraus schließen, dass es sich um einen Erweiterungsklassenlader handeln sollte, denn wenn die von uns geladene Klasse bereits unter dem Pfad des Erweiterungsklassenladers vorhanden ist, ist es falsch, den Systemklassenlader direkt aufzurufen. Die folgende Abbildung zeigt die Überprüfung des nach dem Debuggen erhaltenen Klassenladers. ZusammenfassenTomcat bricht das Prinzip der übergeordneten Delegierung und unterbricht tatsächlich die übergeordnete Delegierung im Anwendungsklassenlader, während andere Klassenlader weiterhin der übergeordneten Delegierung folgen. Dies ist das Ende dieses Artikels über den Tomcat-Klassenlademechanismus. Weitere Informationen zum Tomcat-Klassenlademechanismus finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen! Das könnte Sie auch interessieren:
|
<<: Detaillierte Erklärung der Dreieckszeichnung und clevere Anwendungsbeispiele in CSS
>>: Das kürzeste JS, um festzustellen, ob es sich um IE6 handelt (IE-Schreibmethode)
Inhaltsverzeichnis Erstellen von Zahlungsmethoden...
Klicken Sie hier, um zum Abschnitt „HTML-Tutorial“...
Dieser Artikel veranschaulicht anhand von Beispie...
Vorwort Vue (ausgesprochen /vjuː/, ähnlich wie vi...
Häufige Anwendungsszenarien Die Schnittstellen ak...
Vorbereitung 1. Umgebungsbeschreibung: Betriebssy...
Das Inhaltsattribut wird im Allgemeinen in den Ps...
Wie unten dargestellt: Führen Sie hauptsächlich A...
Inhaltsverzeichnis 1. Projektaussichten 2. Wissen...
Dieser Artikel stellt hauptsächlich die Analyse d...
Gefühle: Ich bin Backend-Entwickler. Manchmal fühl...
Die erste Methode: Verwenden Sie Junges Ein-Klick...
Inhaltsverzeichnis Überblick 1. Trennung von Fron...
MySQL begrenzt die Nutzung von Paging-Anweisungen...
Inhaltsverzeichnis ReagierenHooks Vorwort WarumHo...