Javaクラスローダーの一般的な理解

JVMには、C ++で記述されたクラスローダーとJavaで記述されたクラスローダーの2種類があります。C ++で記述されているBootstrapClass Loader(Bootstrap Class Loader)を除いて、その他はJavaで記述されています。Javaで記述されたクラスローダーは、クラスjava.lang.ClassLoaderから継承します。

さまざまなクラスローダー間に論理的な親子関係があります
ここに画像の説明を挿入

BootClassLoader

スタートアップクラスローダーはC ++で記述されており、スタートアップクラスローダーのコアは次のロジックです。

java.c、入り口LoadMainClass

LoadMainClassは主にcheckAndLoadMainを呼び出し、GetLauncherHelperClassはGetLauncherHelperClassクラスを見つけるために使用され、checkAndLoadMainはGetLauncherHelperClassにあります

checkAndLoadMainは、主にmain関数が配置されているクラスをロードするためのものです。この時点で、拡張クラスローダーとアプリケーションクラスローダーの起動も完了します。

int JNICALL
JavaMain(void * _args)
{
    
    
   ...
    mainClass = LoadMainClass(env, mode, what);
   ...
}


static jclass
LoadMainClass(JNIEnv *env, int mode, char *name)
{
    
    
	jclass cls = GetLauncherHelperClass(env);
		...
    NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls,
                "checkAndLoadMain",
                "(ZILjava/lang/String;)Ljava/lang/Class;"));
    ...
}

jclass
GetLauncherHelperClass(JNIEnv *env)
{
    
    
    if (helperClass == NULL) {
    
    
        NULL_CHECK0(helperClass = FindBootStrapClass(env,
                "sun/launcher/LauncherHelper"));
    }
    return helperClass;
}

概要:このロジックのセットは、クラスローダーを起動してsun.launcher.LauncherHelperクラスをロードし、このクラスのcheckAndLoadMainメソッドを実行して、最後にメイン関数が配置されているクラスのロードを終了します。

親の代表団

親の委任:クラスローダーが特定のクラスをロードする要求を受信した場合、クラスローダーはクラスをロードしませんが、親クラスローダーに要求を委任します。クラスローダーの各レベルにはこれが含まれているため、すべてのクラスのロードリクエストは最終的に最上位のスタートアップクラスローダーに送信されます。親クラスローダーが検索範囲内で必要なクラスを見つけることができず、結果が子クラスローダーにフィードバックされる場合にのみ、子クラスローダーはそれをロードしようとします。それ自体で。
ここに画像の説明を挿入

親の代表団を破る

場合によっては、親クラスローダーが子クラスローダーに委任してクラスファイルをロードする必要があるためです。ロード範囲の制限により、親クラスローダーは必要なファイルをロードできません

例としてjdbcを取り上げます。jdbcはjdkで定義され、その実装は各データベースのサービスプロバイダーによって提供されるため、問題は、DriverManager(jdkによっても提供される)がjdbcインターフェイスを実装する各実装クラスをロードする必要があることです。次にManagementですが、DriverManagerはスタートアップクラスローダーによってロードされ、その実装はサービスプロバイダーによって提供され、アプリケーションクラスローダーによってロードされます。今回は、クラスローダーを起動して、サブクラスに実装クラスのロードを委託する必要があります。したがって、親のデリゲートを破壊します。

親の委任を破ることは、実際には委任せず、下向きに委任することを意味します

親の委任の2つの方法を破る

SPI

SPIはサービス検出メカニズムです。ClassPathパスの下のMETA-INF / servicesフォルダーでファイルを検索し、ファイルで定義されたクラスを自動的にロードします。

SPIメカニズムの下方委任は親の委任を中断します

カスタムクラスローダー

カスタムクラスローダーの例:
classloadの
擬似コードを書き直します:

// 打破双亲委派
if (name.startsWith("com.XXX")) {
    
     
// com.XXX包下的所有类不委派
    c = findClass(name);
} else {
    
    
// 其他包委派
    c = this.getParent().loadClass(name);
}

おすすめ

転載: blog.csdn.net/qq_33873431/article/details/113447921