クラスローダーの分類と関係
- JVMは、2種類のクラスローダーをサポートしています。それらは、ブートストラップクラスローダーとユーザー定義クラス
ローダーです。 - 概念的には、カスタムクラスローダーは通常、プログラム内で開発者がカスタマイズしたクラスローダーを指しますが、Java仮想マシン仕様ではそのように定義されていません。代わりに、抽象クラスから派生したすべてのクラスをロードします。ClassLoaderすべてがカスタムに分割されます。クラスローダー。
次の図に示すように、クラスローダーのタイプがどのように分割されていても、プログラムには常に3つの最も一般的なクラスローダーしかありません。
注:JDK1.9以降、拡張クラスローダーExtClassLoaderはPlatFromClassLoaderプラットフォームローダーになります。
ここでの4つは封じ込め関係であり、上位層と下位層ではなく、サブシステムの継承関係でもありません。
クラスを渡して、さまざまなローダーを取得します。
public class ClassLoaderTest {
public static void main(String[] args) {
//获取系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
//获取其上层的:扩展类加载器
ClassLoader classLoaderParent = systemClassLoader.getParent();
System.out.println(classLoaderParent);
//获取根加载器
ClassLoader loaderParentParent = classLoaderParent.getParent();
System.out.println(loaderParentParent);
//获取自定义加载器
ClassLoader loader = ClassLoaderTest.class.getClassLoader();
System.out.println(loader);
//获取String类型的加载器
ClassLoader classLoader = String.class.getClassLoader();
System.out.println(classLoader);
}
}
結果から、ルートローダーをコードから直接取得することはできず、ユーザーコードで現在使用されているローダーはシステムクラスローダーであることがわかります。同時に、String型のローダーを取得し、それがnullであることを確認します。これは、String型がルートローダーを介してロードされることを意味します。つまり、Javaのコアクラスライブラリはルートローダーを使用してロードされます。
jdk.internal.loader.ClassLoaders$AppClassLoader@2437c6dc
jdk.internal.loader.ClassLoaders$PlatformClassLoader@58ceff1
null
jdk.internal.loader.ClassLoaders$AppClassLoader@2437c6dc
null
注:ここでのPlatformClassLoaderは、ExtClassLoaderと見なすことができます。
仮想マシンに付属のローダー
クラスローダーを起動します(ブートストラップクラスローダー、ブートストラップクラスローダー)
- このクラスローダーはC / C ++言語で実装され、JVM内にネストされています。
- これは、コアJavaライブラリ(JAVAHOME / jre / 1ib / rt.jar、resources.jar、またはsun.boot.class.pathのパスの下にあるコンテンツ)をロードして、JVM自体に必要なクラスを提供するために使用されます。
- java.lang.ClassLoaderから継承せず、親ローダーもありません。
- 拡張クラスローダーとアプリケーションクラスローダーをロードし、それらを親クラスローダーとして指定します。
- セキュリティ上の理由から、Bootstrapスタートアップクラスローダーは、パッケージ名がjava、javax、sunなどで始まるクラスのみをロードします。
拡張クラスローダー
- Java言語で記述されたJDK1.8は、sun.misc.Launcher $ ExtClassLoaderによって実装されます。JDK1.9以降は、PlatFromClassLoaderに変更され、jdk.internal.loader.PlatformClassLoaderによって実装されます。
- ClassLoaderクラスから派生。
- 親クラスローダーは、スタートアップクラスローダーです。
- java.ext.dirsシステムプロパティで指定されたディレクトリからクラスライブラリをロードするか、JDKインストールディレクトリのjre / lib / extサブディレクトリ(拡張ディレクトリ)からクラスライブラリをロードします。ユーザーが作成したJARがこのディレクトリに配置されている場合、拡張クラスローダーによって自動的にロードされます。
アプリケーションクラスローダー(システムクラスローダー、AppClassLoader)
- Java言語で記述され、sun.misc.LaunchersAppClassLoaderによって実装されます。
- ClassLoaderクラスから派生。
- 親クラスローダーは拡張クラスローダーです。
- これは、環境変数classpathまたはシステムプロパティjava.class.pathで指定されたパスの下にクラスライブラリをロードする役割を果たします。
- このクラスロードは、プログラムのデフォルトのクラスローダーです。一般的に、Javaアプリケーションクラスはそれによってロードされます
。クラスローダーは、classLoader#getSystemclassLoader()メソッドを介して取得できます。
ユーザー定義のクラスローダー
Javaの日常のアプリケーション開発では、クラスのロードはほとんど上記の3種類のローダーの調整によって実行されますが、必要に応じて、クラスローダーをカスタマイズしてクラスのロード方法をカスタマイズすることもできます。なぜクラスローダーをカスタマイズしたいのですか?
- クラスを分離してロードする
- クラスのロード方法を変更する
- 拡張機能の読み込みソース
- ソースコードの漏洩を防ぐ
ユーザー定義のクラスローダーの実装手順:
- 開発者は、いくつかの特別なニーズを満たすために抽象クラスJava.lang.ClassLoaderを継承することにより、独自のクラスローダーを実装できます。
- JDK1.2より前は、クラスローダーをカスタマイズするときに、常にClassLoaderクラスを継承し、loadClass()メソッドを書き直して、カスタムクラスローディングクラスを実現していましたが、JDK1.2以降、ユーザーが1oadclass()をオーバーライドすることは推奨されなくなりました。メソッドですが、findclass()メソッドでカスタムクラスローディングロジックを作成することをお勧めします。
- カスタムクラスローダーを作成するときに、要件がそれほど複雑でない場合は、URIClassLoaderクラスを直接継承できるため、独自のfindclass()メソッドやバイトコードストリームを取得する方法を作成する必要がなくなり、次のことが可能になります。カスタムクラスローダー記述はより簡潔です。
ClassLoaderクラス
ClassLoaderクラス。これは抽象クラスであり、後続のすべてのクラスローダーはClassLoaderから継承します(スタートアップクラスローダーは含まれません)。
ClassLoaderを取得する方法:
- 現在のClassLoaderを取得します:clazz.getClassLoader()
- 現在のスレッドコンテキストのClassLoaderを取得します:Thread.currentThread()。getContextClassLoader()
- システムのClassLoaderを取得します:ClassLoader.getSystemClassLoader()
- 呼び出し元のClassLoaderを取得します:DriverManager.getCallerClassLoader()