Prozess des Klassenlademechanismus von Tomcat und Quellcodeanalyse

Prozess des Klassenlademechanismus von Tomcat und Quellcodeanalyse

Vorwort

Im vorherigen Artikel „Java Virtual Machine: Objekterstellungsprozess und Klassenlademechanismus, übergeordnetes Delegationsmodell“ haben wir den JVM-Klassenlademechanismus und das übergeordnete Delegationsmodell vorgestellt. Der Klassenladeprozess des übergeordneten Delegationsmodells ist hauptsächlich in die folgenden Schritte unterteilt:

(1) Beim Initialisieren von ClassLoader müssen Sie angeben, wer Ihr übergeordnetes Element ist

(2) Überprüfen Sie zunächst, ob die Klasse geladen wurde. Wenn die Klasse geladen wurde, kehren Sie direkt zurück

(3) Wenn es nicht geladen ist, rufen Sie die loadClass () -Methode des übergeordneten Loaders auf, um es zu laden

(4) Wenn der übergeordnete Loader leer ist, wird standardmäßig der Bootstrap ClassLoader zum Laden verwendet

(5) Wenn das Laden der übergeordneten Klasse fehlschlägt, wird eine ClassNotFoundException ausgelöst und anschließend die Methode findClass() aufgerufen, um sie zu laden.

Wenn Sie diesen Mechanismus zerstören möchten, können Sie, wie im vorherigen Artikel erwähnt, einen Klassenlader (geerbt von ClassLoader) anpassen und die loadClass()-Methode darin neu schreiben, sodass sie keine übergeordnete Delegierung durchführt. Das klassischste Beispiel ist der Klassenlademechanismus des Tomcat-Containers, der seinen eigenen Klassenlader WebApp ClassLoader implementiert und das übergeordnete Delegierungsmodell unterbricht. Nach der Bereitstellung jeder Anwendung wird ein eindeutiger Klassenlader erstellt.

1. Strukturdiagramm des Tomcat-Klassenladers:

(1) Common ClassLoader: Lädt das JAR unter der Eigenschaft common.loader, normalerweise im Verzeichnis CATALINA_HOME / lib, das hauptsächlich von Tomcat und einigen gängigen Anwendungsklassen verwendet wird

(2) Catalina ClassLoader: Lädt das JAR unter der Eigenschaft server.loader. Standardmäßig ist kein Pfad konfiguriert und der übergeordnete Loader, Common ClassLoader, wird zurückgegeben. Er lädt hauptsächlich sichtbare Klassen innerhalb des Servers. Auf diese Klassen kann von Anwendungen nicht zugegriffen werden.

(3) Shared Classloader: Lädt das JAR unter dem Attribut share.loader. Standardmäßig ist kein Pfad konfiguriert und der übergeordnete Loader, Common ClassLoader, wird zurückgegeben. Er wird hauptsächlich zum Laden gemeinsam genutzter Anwendungsklassen verwendet. Diese Klassen sind für Tomcat selbst nicht sichtbar.

Erst wenn die Elemente server.loader und share.loader in der Konfigurationsdatei tomcat/conf/catalina.properties angegeben sind, werden die Instanzen von Catalina ClassLoader und Shared ClassLoader tatsächlich erstellt. Andernfalls werden anstelle dieser beiden Klassenlader die Instanzen von Common ClassLoader verwendet. Diese beiden Loader-Elemente sind jedoch in der Standardkonfigurationsdatei nicht festgelegt.

(4) WebApp ClassLoader: Tomcat kann mehrere WebApp ClassLoader-Instanzen haben. Jede Anwendung hat einen eigenen WebApp ClassLoader, um die Klassen unter /WEB-INF/classes und /WEB-INF/lib der Anwendung zu laden.

2. Beschreibung des Klassenladevorgangs von Tomcat:

Wenn Tomcat WebAppClassLoader zum Laden von Klassen verwendet, sieht der konkrete Vorgang wie folgt aus:

(1) Überprüfen Sie zunächst, ob die Klasse in den lokalen Cache geladen wurde, um zu sehen, ob Tomcat die Klasse geladen hat.

(2) Wenn Tomcat diese Klasse nicht geladen hat, überprüft er den Cache des Systemklassenladers, um festzustellen, ob sie geladen wurde.

(3) Wenn nicht, verwenden Sie den ExtClassLoader-Klassenlader, um die Klasse zu laden. Hier kommt der Punkt. Tomcats WebAppClassLoader verwendet nicht zuerst AppClassLoader, um die Klasse zu laden, sondern verwendet direkt ExtClassLoader, um die Klasse zu laden. ExtClassLoader folgt jedoch weiterhin der übergeordneten Delegierung. Es verwendet Bootstrap ClassLoader zum Laden von Klassen und stellt so sicher, dass die Kernklassen in Jre nicht wiederholt geladen werden.

Beispielsweise das Laden einer Objektklasse im Web. WebAppClassLoader → ExtClassLoader → Bootstrap ClassLoader, diese Ladekette stellt sicher, dass das Objekt nicht wiederholt geladen wird.

(4) Wenn das Laden nicht erfolgreich ist, ruft WebAppClassLoader seine eigene Methode findClass() auf, um die Klasse selbst zu laden. Dabei lädt es sie zuerst aus WEB-INF/classes und dann aus WEB-INF/lib.

(5) Wenn das Laden immer noch nicht erfolgreich ist, delegiert WebAppclassLoader an SharedClassLoader, SharedClassLoader delegiert an CommonClassLoader, CommonClassLoader delegiert an AppClassLoader, bis es schließlich an BootstrapClassLoader delegiert wird und die Klasse schließlich Schicht für Schicht in ihr eigenes Verzeichnis lädt.

(6) Wenn keine der Dateien erfolgreich geladen werden konnte, wird eine Ausnahme ausgelöst.

3. Quellcode-Analyse:

(1) Quellcode der loadClass()-Methode von WebAppClassLoader:

WebappClassLoader-Anwendungsklassenlader loadClass in seiner übergeordneten Klasse WebappClassLoaderBase

öffentliche Klasse<?> loadClass(Stringname, Boolesche Auflösung) wirft ClassNotFoundException {
    synchronisiert (getClassLoadingLock(name)) {
        Klasse<?> clazz = null;
        //1. Prüfen Sie zunächst im lokalen Cache, ob die Klasse geladen wurde. clazz = findLoadedClass0(name);
        if (clazz != null) {
            wenn (auflösen)
                Klasse auflösen(clazz);
            Rückgabeklazz;
        }
        //2. Prüfen Sie, ob der Systemklassenlader clazz = findLoadedClass(name); geladen hat.
        if (clazz != null) {
            wenn (auflösen)
                Klasse auflösen(clazz);
            Rückgabeklazz;
        }
        // 3. Versuchen Sie, die Klasse mit dem Klassenlader ExtClassLoader zu laden (ExtClassLoader befolgt die übergeordnete Delegierung, ExtClassLoader verwendet Bootstrap ClassLoader zum Laden der Klasse).
        Ich habe versucht, den ClassLoader zu starten, aber ich habe ihn nicht gestartet.
        versuchen {
            clazz = javaseLoader.loadClass(name);
            if (clazz != null) {
                wenn (auflösen)
                    Klasse auflösen(clazz);
                Rückgabeklazz;
            }
        } Fang (ClassNotFoundException e) {
            // Ignorieren
        }
        // 4. Versuche die Klasse im lokalen Verzeichnis zu suchen und zu laden try {
            clazz = Klasse finden(Name);
            if (clazz != null) {
                wenn (auflösen)
                    Klasse auflösen(clazz);
                Rückgabeklazz;
            }
        } Fang (ClassNotFoundException e) {
            // Ignorieren
        }
        // 5. Versuchen Sie, mit dem Systemklassenlader (AppClassLoader) zu laden try {
            clazz = Klasse.forName(Name, falsch, übergeordnetes Element);
            if (clazz != null) {
                wenn (auflösen)
                    Klasse auflösen(clazz);
                Rückgabeklazz;
            }
        } Fang (ClassNotFoundException e) {
            // Ignorieren
        }
     }
    //6. Das Laden der oben genannten Prozesse schlägt fehl und es wird eine Ausnahme ausgelöst: throw new ClassNotFoundException(name);
}

(2) Quellcode der findClass()-Methode von WebAppClassLoader:

öffentliche Klasse<?> findClass(String name) löst ClassNotFoundException { aus
    // Bitten Sie unsere Superklasse, diese Klasse zu lokalisieren, falls möglich
    // (löst ClassNotFoundException aus, wenn es nicht gefunden wird)
    Klasse<?> clazz = null;
 
    // Suchen Sie zuerst im eigenen Web-Anwendungsverzeichnis nach der Klasse
    clazz = findClassInternal(name);
 
    // Kann es nicht finden und lass es von der übergeordneten Klasse verarbeiten, wenn ((clazz == null) && hasExternalRepositories) {  
        clazz = super.findClass(name);
    }
    wenn (clazz == null) {
         wirf eine neue ClassNotFoundException(Name);
    }
    Rückgabeklazz;
}

4. Warum implementiert Tomcat einen eigenen Mechanismus zum Laden von Klassen?

Wenn WebAppClassLoader Klassen lädt, unterbricht es absichtlich den übergeordneten Delegierungsmechanismus der JVM, umgeht AppClassLoader und verwendet ExtClassLoader direkt zum Laden von Klassen. Der Hauptgrund besteht darin, sicherzustellen, dass die von verschiedenen, auf demselben Webcontainer bereitgestellten Webanwendungen verwendeten Klassenbibliotheken voneinander isoliert werden können, um eine gegenseitige Beeinflussung zwischen verschiedenen Projekten zu vermeiden. Natürlich gibt es auch andere Gründe, wie zum Beispiel:

(1) Stellen Sie sicher, dass die Sicherheit des Webcontainers selbst nicht durch die bereitgestellte Webanwendung beeinträchtigt wird. Daher muss die von Tomcat verwendete Klassenbibliothek unabhängig von der Klassenbibliothek der bereitgestellten Anwendung sein.

(2) Stellen Sie sicher, dass einige grundlegende Klassen nicht gleichzeitig geladen werden. Einige Klassenbibliotheken können zwischen Tomcat und bereitgestellten Anwendungen gemeinsam genutzt werden, z. B. Servlet-API

(3) Stellen Sie sicher, dass Klassenbibliotheken zwischen Anwendungen, die im selben Webcontainer bereitgestellt werden, gemeinsam genutzt werden können. Dies klingt nach widersprüchlichen Hauptgründen, ist aber in Wirklichkeit sehr vernünftig. Nachdem die Klasse vom Klassenlader in die virtuelle Maschine geladen wurde, wird sie im permanenten Generierungsmethodenbereich gespeichert. Wenn die Klassenbibliothek nicht gemeinsam genutzt werden kann, besteht leicht die Gefahr einer übermäßigen Erweiterung des Methodenbereichs der virtuellen Maschine. Wenn beispielsweise eine große Anzahl von Anwendungen von Spring verwaltet wird und die Spring-Klassenbibliothek nicht gemeinsam genutzt werden kann, wird die Spring-Klassenbibliothek jeder Anwendung einmal geladen, was eine enorme Ressourcenverschwendung darstellt.

Zusammenfassung: In Tomcat unterbricht nur der WebAppClassLoader die übergeordnete Delegierung, während andere Klassenlader weiterhin der übergeordneten Delegierung folgen. Der Hauptgrund hierfür besteht darin, sicherzustellen, dass die von verschiedenen Web-Anwendungen im selben Web-Container verwendeten Klassenbibliotheken voneinander unabhängig sind, um gegenseitige Störungen zu vermeiden.

Referenzartikel: https://www.jb51.net/article/229561.htm

Dies ist das Ende dieses Artikels über den Klassenlademechanismus von Tomcat und die Quellcodeanalyse. Weitere relevante Inhalte zum Klassenlademechanismus von Tomcat finden Sie in den vorherigen Artikeln von 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird!

Das könnte Sie auch interessieren:
  • Implementierungsmethode und Beispielcode des Tomcat-Klassenladers

<<:  Vergleich der Effizienz zwischen Einzeltabellenabfrage und Mehrtabellen-Joinabfrage in der MySql-Datenbank

>>:  Informationen zum Debuggen von CSS-Cross-Browser-Style-Fehlern

Artikel empfehlen

Erfahren Sie in fünf Minuten mehr über React Routing

Inhaltsverzeichnis Was ist Routing Grundlegende V...

So beschränken Sie das Eingabefeld in HTML auf die Eingabe reiner Zahlen

Beschränken Sie input Eingabefeld auf reine Zahle...

Lösungen zur Verarbeitung und Reparatur historischer Linux-Images

Der ECS-Cloud-Server, der mit dem historischen Li...

Python 3.7-Installationstutorial für MacBook

Der detaillierte Prozess der Installation von Pyt...

Detaillierte Erläuterung des Prinzips der Vue-Überwachungsdaten

Inhaltsverzeichnis 1. Einleitung II. Überwachungs...

React implementiert eine mehrkomponentige Wertübertragungsfunktion über Conetxt

Die Wirkung dieser Funktion ist ähnlich wie vue的p...

JavaScript zum Erzielen eines Texterweiterungs- und -reduzierungseffekts

Die Implementierung des Erweiterns und Reduzieren...

So verwenden Sie Docker, um Containerressourcen zu begrenzen

Problem beim Gucken Angenommen, der IIS-Dienst st...

So verwenden Sie Shell-Skripte in Node

Hintergrund Während der Entwicklung benötigen wir...

So konfigurieren Sie eine VMware-Umgebung mit mehreren Knoten

Dieses Tutorial verwendet CentOS 7 64-Bit. Weisen...

SQL-Implementierung von LeetCode (197. Steigende Temperatur)

[LeetCode] 197.Steigende Temperatur Schreiben Sie...

mysql ist keine interne Befehlsfehlerlösung

Der Fehler „mysql ist kein interner Befehl“ tritt...