ClassLoaderは、JVMにおける特別なコンポーネントであり、クラスが初めて使用される際にバイトコードをメモリにロードする役割を担っています。これは、動的にさまざまなソース(ファイルシステム、ネットワーク、アーカイブなど)からクラスをロードすることを可能にします。
クラスローダーの種類:
jre/lib/extパスから拡張機能をロードします。ClassLoaderは委任を実装しています:まず親ローダーを介してクラスをロードしようとし(親優先)、失敗した場合にのみ自分自身を検索します。
クラスの隔離: 各クラスローダーは独自の"クラスのスコープ"を作成します。同名の2つのクラスを異なるローダーでロードした場合、JVM内で異なるタイプと見なされます。
カスタムローダーの作成例:
class MyClassLoader extends ClassLoader { @Override protected Class<?> findClass(String name) throws ClassNotFoundException { // クラスのバイトコードを検索してロードするコード return super.findClass(name); } }
異なるローダーでロードされた同名のクラスは、JVM内で同じクラスと見なされることがありますか?
回答: いいえ!JVMはクラスを(クラス名の完全名、クラスローダー)のペアでユニークなものと見なします。したがって、異なるローダーでロードされた同じクラスは異なるものと見なされます。
物語
プラグインアーキテクチャをサポートするエンタープライズアプリケーションでは、プラグインが異なるクラスローダーでロードされていました。そのため、メインアプリケーションとプラグイン間でインターフェース(PluginInterface)タイプのオブジェクトを渡そうとするとClassCastExceptionが発生しました。なぜなら、同じインターフェースが異なるローダーでロードされていたからです。
物語
カスタムクラスローダーを使用する際に、親ローダーへの委任が実装されていませんでした。これにより、標準ライブラリクラスが再度ロードされ、奇妙なClassCastExceptionやLinkageErrorを引き起こしました。
物語
大規模なJava EEサーバーでは、異なるアプリケーションが同じライブラリの異なるバージョンをロードしていました。ローダーのチェーン設定に不注意があったため、アプリケーション間でクラスが交差し、一度は大規模なメモリリークとバージョンの競合による障害を引き起こしました。