Learn · concepts

Was ist ein Java-Klassenlader?

Ein Classloader findet und lädt Java-Klassen zur Laufzeit in die JVM. Hier erfahren Sie, wie sie funktionieren, warum die Hierarchie wichtig ist und warum Mods davon abhängig sind.

TRtrolPublished 5 min read

Ein Classloader ist der Teil der Java Runtime Environment, der eine Klassendatei findet und sie in die JVM lädt. Jedes Mal, wenn Ihr Code einen Typ zum ersten Mal verwendet, fragt die JVM einen Classloader: "Finde diese Klasse für mich." Der Loader lokalisiert den Bytecode, liest ihn, und die JVM definiert die Klasse im Speicher. Dieser Mechanismus ist in normalen Java-Programmen unsichtbar, stellt aber den genauen Ankerpunkt dar, den Mod-Frameworks nutzen, um Minecraft zu patchen.

Was ein Classloader tatsächlich tut

Ein Classloader wandelt einen Klassennamen in eine nutzbare Klasse innerhalb der laufenden JVM um. Sie fordern einen Typ an, der Loader findet die passende .class-Datei (oder generiert sie), verifiziert und verknüpft sie, und die Klasse ist bereit zur Verwendung.

Die Arbeit erfolgt in drei Schritten:

  1. Finden — Der Loader lokalisiert den Bytecode für die benannte Klasse (aus einer JAR-Datei, von der Festplatte, dem Netzwerk oder generiert zur Laufzeit).
  2. Verifizieren und Verknüpfen — Die JVM prüft, ob der Bytecode gültig ist, und löst Referenzen auf andere Klassen auf.
  3. Verwenden — Die Klasse ist bereit und Ihr Programm kann sie instanziieren.

Deshalb können Java-Programme Code dynamisch zur Laufzeit laden, der zur Kompilierzeit nie erwähnt wurde. Der Klassenname genügt dem Loader, um ihn zu finden.

Die Classloader-Hierarchie

Classloader sind in einer Eltern-Kind-Kette angeordnet, und die meisten von ihnen fragen zuerst ihren Eltern. Eine Standard-Java-Anwendung hat drei integrierte Classloader:

LoaderLoadsZweck
BootstrapKern-Java-Runtime-KlassenStellt sicher, dass Kern-Typen wie java.lang.Object immer gleich sind
PlattformStandardbibliotheksmodule außerhalb des KernsJava-Module und -Erweiterungen
AnwendungDie eigenen Klassen Ihres ProgrammsDer Klassenpfad, den Ihr Programm angibt

Wenn der Anwendungslader nach einer Klasse gefragt wird, delegiert er normalerweise zuerst nach oben. Er fragt den Plattformlader, der den Bootstrap-Lader fragt, der versucht, sie zu laden. Nur wenn kein Elternteil sie laden kann, versucht das Kind. Dies ist das Delegationsmodell und verhindert, dass dieselbe Klasse zweimal unter unterschiedlichen Namen geladen wird.

Klassenidentität und Funktionsweise

Eine Klasse wird sowohl durch ihren Namen als auch durch den Lader, der sie definiert hat, identifiziert. Zwei verschiedene Lader können jeweils eine Klasse namens com.example.MyClass laden, und die JVM behandelt sie als zwei völlig unterschiedliche Typen. Das mag obskur klingen, ist aber die Grundlage für alles Interessante, was Java kann.

Bootstrap Loader: java.lang.Object (the core Object)
Application Loader: java.lang.Object (if somehow re-loaded by app loader)
→ Two different types, same name
→ This breaks your program, which is why delegation prevents it

Benutzerdefinierte Klassenlader

Programme können eigene Klassenlader definieren. Ein benutzerdefinierter Lader kann Bytecode von überall lesen: aus einer JAR-Datei, dem Netzwerk, einer Datenbank oder aus Bytecode, das er zur Laufzeit generiert oder transformiert hat. Dies geschieht wie folgt:

  • Plugin-Systeme laden Code dynamisch, ohne ihn zur Kompilierzeit zu kennen.
  • App-Server (Tomcat, JBoss) führen mehrere Anwendungen in derselben JVM aus, jede mit ihrem eigenen Classloader.
  • Minecraft-Mods patchen Spielklassen während des Ladens.

Warum das für Minecraft-Mods wichtig ist

Mods existieren aufgrund von benutzerdefiniertem Classloading. Ein Mod-Loader für Minecraft startet das Spiel über seinen eigenen benutzerdefinierten Classloader, um Spielklassen beim Laden zu sehen und zu modifizieren. Dieser Abfangpunkt ist der Ort, an dem die Magie geschieht.

Wenn ein Loader zwischen der Festplatte und der JVM sitzt, kann er eine Klasse direkt vor der Definition durch die JVM verändern:

Disk: obfuscated Minecraft class
    ↓
Mod Loader (custom classloader)
    ↓ [bytecode transformation happens here]
    ↓
JVM: defines the patched class
    ↓
Memory: game runs with mods active

Ein Mod kann eine Spielmethode umschreiben, neues Verhalten injizieren, Felder hinzufügen, ohne die Spiel-JAR-Datei auf der Festplatte zu berühren. Die Klasse, die die JVM letztendlich ausführt, ist die, die vom Mod-Framework modifiziert wurde. Dies ist genau so, wie Fabric, Forge und andere Mod-Loader Minecraft patchen.

Lazy Loading

Klassen werden nicht alle beim Start geladen. Die JVM lädt jede Klasse beim ersten tatsächlichen Gebrauch. Dies wird als Lazy Loading bezeichnet:

Program starts → JVM doesn't load String class yet
User calls System.out.println() → String is needed → Loader loads it

Das bedeutet, dass ein Classloader nur Klassen finden und laden muss, die Ihr Code tatsächlich berührt. Unbenutzte Klassen gelangen nie in den Speicher. Deshalb kann der Minecraft-Start eine Weile dauern (Mods fügen viele Klassen hinzu), aber nicht für immer einfrieren.

FAQ