Learn · concepts

Java クラスローダーとは何ですか??

クラスローダーは、実行時にJVMにJavaクラスを見つけてロードします。それらがどのように機能するか、階層がなぜ重要なのか、そしてmodがそれらに依存する理由について説明します.

TRtrolPublished 1 min read

クラスローダーは、Javaランタイムの一部であり、クラスファイルを見つけてJVMにロードする役割を担います。コードが型に初めてアクセスするたびに、JVMはクラスローダーに「このクラスを見つけてくれ」と問い合わせます。ローダーはバイトコードを特定し、読み込み、JVMはメモリ内にクラスを定義します。この仕組みは通常のJavaプログラムでは不可視ですが、modフレームワークがMinecraftをパッチ適用するために使用するまさにそのフックです。

クラスローダーが実際に何をしているのか

クラスローダーは、クラス名を実行中のJVM内で使用可能なクラスに変換します。ある型を要求すると、ローダーが対応する.classファイル(または生成されたもの)を見つけ、検証およびリンクを行い、クラスが使用できるようになります。

この作業は3つのステップで行われます。

  1. 検索 — ローダーは、指定されたクラスのバイトコードを特定します(JARファイル、ディスク、ネットワーク、またはオンザフライで生成されたものから)。
  2. 検証とリンク — JVMは、バイトコードが有効であり、他のクラスへの参照が解決されることを確認します。
  3. 使用 — クラスが使用可能になり、プログラムがインスタンス化できるようになります。

これにより、Javaプログラムはコンパイル時に言及されなかったコードを実行時に動的にロードできます。クラス名があれば、ローダーがそれを探し出すことができます。

クラスローダーの階層構造

クラスローダーは親チェーンで構成されており、そのうちのほとんどが最初に親に問い合わせます。標準的なJavaアプリケーションには、3つの組み込みクラスローダーがあります

ローダー負荷目的
BootstrapローダーコアJavaランタイムクラスjava.lang.Objectのようなコア型が常に同じであることを保証します
プラットフォームローダーコア外の標準ライブラリモジュールJavaモジュールと拡張機能
アプリケーションローダーあなたのプログラム自身のクラスあなたのプログラムが指定するクラスパス

アプリケーションローダーがクラスを要求された場合、通常はまず上位に委譲します。プラットフォームローダーに問い合わせ、プラットフォームローダーがBootstrapローダーに問い合わせ、それがロードを試みます。親がロードできない場合にのみ、子ローダーが試みます。これが委譲モデルであり、同じクラスが異なる名前で2回ロードされるのを防ぎます。

クラスの識別と仕組み

クラスは、その名前それを定義したローダーの両方によって識別されます。2つの異なるローダーがそれぞれcom.example.MyClassというクラスをロードできる場合、JVMはそれらを完全に異なる型として扱います。これは難解に聞こえるかもしれませんが、Javaができる興味深いことの基礎となっています。

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

カスタムクラスローダー

プログラムは独自のクラスローダーを定義できます。カスタムローダーは、JARファイル、ネットワーク、データベース、またはその場で生成または変換したバイトコードなど、どこからでもバイトコードを読み取ることができます。その方法は次のとおりです

  • プラグインシステムは、コンパイル時にその存在を知らなくても、コードを動的にロードします。
  • アプリケーションサーバー(Tomcat、JBoss)は、同じJVM内で複数のアプリケーションを実行し、それぞれ独自のクラスローダーを持ちます。
  • MinecraftのMODは、ロード時にゲームクラスをパッチします。

MinecraftのMODにとって、なぜこれが重要なのか

MODはカスタムクラスローディングによって存在します。MinecraftのMODローダーは、独自のカスタムクラスローダーでゲームを開始し、ロード時にゲームクラスを表示し、変更できるようにします。そのインターセプトポイントが魔法が起こる場所です。

ローダーがディスクとJVMの間に位置すると、JVMが定義する直前にクラスを変換できます。

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

MODはゲームメソッドを書き換えたり、新しい動作を注入したり、フィールドを追加したりできます。すべてゲームJARをディスク上で変更せずに実行できます。JVMが実際に実行するのは、MODフレームワークによって変更されたクラスです。これが、Fabric、Forge、その他のMODローダーがMinecraftをパッチする方法です。

怠惰なロード

クラスはすべて起動時にロードされるわけではありません。JVMは、実際に使用されるときに初めてクラスをロードします。これは怠惰なロードと呼ばれます。

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

これは、クラスローダーが実際にコードが触れるクラスのみを見つけてロードする必要があることを意味します。未使用のクラスはメモリに入りません。これが、Minecraftの起動に時間がかかる理由(MODがクラスをたくさん追加するため)ですが、永久にフリーズすることはありません。

FAQ