Javaには2つのタイプのクラスロードがあり、1つはJVMに組み込まれたブートストラップクラスローダーです。
JVMに組み込まれた3種類のクラスローダー、つまりBootstrapクラスローダー、拡張機能クラスローダー(つまり、ExtClassLoader)、およびSystem ClassLoader(つまり、AppClassLoader)があります。
JVMがロードされたときに親の代表団については話しません。Javaeyeに関する多くの記事が紹介されています...
ブートストラップクラスローダーがcで記述されているコンストラクターを個別に見ることができます。
java.lang.classloader
Protected ClassLoader(ClassLoader){SecurityManager.getSecurityManager(); true;初期化= true;
このコンストラクターには2つのパラメーターがあり、コンストラクターはありません。このクラスローダーの親ローダーにパラメーターを通過しますが、パラメーターのないコンストラクターは、getsystemclassloader()を見てみましょう
public static classloader getsystemclassloader(){// Initsystemclassloader(); ccl = getCallerClassLoader(); if(!sclset){if(scl!= null)sun.misc.launcher l = sun.mis c.launcher.getlauncher(); oops = null; //値はscl = l.getClassLoader()に割り当てられます。 ...............................}} sclset = true;ここの親クラスローダーはSCLで、L.GetClassLoader()、GetClassLoader()によって取得され、Launcherのソースコードを確認します。
プライベート静的ランチャーランチャー= new Launcher();
public static launcher getLauncher(){Return Launcher; ;)catch(ioException e){"internation class loaderを作成できませんでした} AppClassLoader、つまり、GetSystemClassLoaderはAppClassLoader.GetClassLoader(ExtCL)を返しますスレッド、マルチスレッドのクラスロードによる混乱(私は自分自身を理解しています)//プライマリスレッドのコンテキストクラスローダーも設定します。 ................................................. .................................................. ..............} / * *メインアプリケーションの起動に使用されるクラスローダーを返します。このことから、AppClassLoaderの親ローダーはExtClassLoaderであることがわかります。また、ExtClassLoaderの親ローダーは何ですか? extclassloaderコンストラクターを見てみましょう。
public extclassloader(file [] dirs)は、super(getexturls(dirs)、null、factory)をスローします。
彼の親は空で、彼のトップレベルの親クラスはjava.lang.classloaderです。
保護された同期クラス<?> loadclass(string name、boolean resolve)は、classnotfoundexceptionをスローします。最初に、クラスがすでにロードされているかどうかを確認します!= null){//最初にload.loadclass(name、false); ){まだ見つかっていない場合は、順番にclassを見つけます。ここでは、FindBootStrapClass0は、最もコアクラスローダーであるBootstrapクラスローダーを呼び出してクラスをロードします。
最後に、getsystemclassloader()によって返されるクラスローダーがAppClassLoaderであることがわかります。
Javaクラスローダーメカニズム分析
JDKデフォルトのクラスローダー
JDKは、デフォルトで次のクラスローダーを提供します
bootstrpローダー
Bootstrpローダーは、Java Virtual Machineが開始された後、C ++言語で記述されます。 JRE/クラス。
extclassloader
bootstrpローダーは、extclassloaderをロードし、extclassloaderの親ローダーをBootStrpローダーに設定します。このすべてのクラスディレクトリjava.ext.dirsシステム変数によって指定されたパス内のパスおよびクラスライブラリの下にあります。
AppClassLoader
bootstrpローダーがextclassloaderをロードすると、AppClassloaderがロードされ、AppClassLoaderの親ローダーがExtClassLoaderとして指定されます。 AppClassloaderは、sun.misc.launcher $ appclassloaderでもあります。これはJARドキュメントであり、Javaプログラムのデフォルトのクラスローダーでもあります。
要約すると、それらの間の関係は次の図で説明できます。
親委任モデル
Javaでのクラスローダーの読み込みは、親の代表的なメカニズムを使用してクラスをロードする場合、次の手順を採用します。
現在、ClassLoaderは、このクラスがすでにロードされている場合、クラスからロードされているかどうかを確認します。
各クラスのローダーには、クラスがロードされると、キャッシュに入れられ、次回ロードされると直接返されます。
Classloaderキャッシュが見つかった場合、親クラスのローダーは最初に同じ戦略を採用し、親クラスのすべてのロードを委任します。 bootstrp classloaderへの方法。
すべての親クラスローダーがロードされていない場合、それらは現在のクラスローダーによってロードされ、独自のキャッシュに入れて、次回ロードリクエストがあるときに直接返すことができます。
これについて言えば、なぜJavaはそのような委任メカニズムを採用しているのだろうと思うかもしれません。この問題を理解するには、クラスローダーに関する別の概念「名前空間」を紹介します。つまり、特定のクラスを決定するには、クラスの完全な資格のある名前が必要であり、このクラスクラスローダーをロードして共同で決定する必要があります。つまり、2つのクラスの完全な資格のある名前が同じであっても、このクラスが異なるクラスをロードするため、JVMの別のクラスです。名前空間を理解した後、デリゲートモデルを見てみましょう。代表モデルを採用した後、さまざまなクラスローダーのインタラクティブな機能が増加します。たとえば、Hashmap、LinkedListなどのJDK Binshengが提供するクラスライブラリは増加します。あなたのプログラムは非常に多くのクラスローダーが含まれているため、これらのクラスは実際に共有できます。これは、同じ名前の異なるクラスを読み込んだ後、異なるクラスローダーによって引き起こされる混乱を避けます。
クラスローダーをカスタマイズする方法
上記のデフォルトのクラスローダーに加えて、クラスローダーをカスタマイズする場合は、java.lang.classloaderを継承する必要があります。いくつかの重要な方法に注意を払う必要があります。
1.ロードクラスメソッド
LoadClassメソッドは宣言します
public class <?> loadclass(string name)classNotFoundExceptionをスローします
上記は、上記の親の委任メカニズムの実装のプロトタイプ宣言です。この方法のコードを見て、それが親の委任をどのように実施するかを見てみましょう。
LoadClassメソッド実装
パブリッククラス<?
上記から、LoadClassメソッドがLoadCclass(Name、False)メソッドを呼び出すことがわかります。そのため、別のLoadClassメソッドの実装を見てみましょう。
クラスLoadClass(String Name、Boolean Resolve)
保護された同期クラス<? = null){try {if(parent!= null){c = parent.loadclass(name、false); } else {c = findbootstrapclass0(name); //親クラスローダーがない場合は、ブートストラップローダーを委任してロードして}} catch(classNotFoundException e){//クラスを見つけるc = findclass(name); }} if(resolve){resolveclass(c);}上記のコードでは、コメントを追加して、LoadClassの親委任メカニズムがどのように機能するかを明確に確認しました。 ここで注意する必要があることの1つは、Public Class <?さらに、上記のFindClassメソッドがあることに気付きました。
2.ファインドクラス
java.lang.classloaderのソースコードを確認すると、FindClassの実装は次のとおりです。
Protected class <?
この方法のデフォルトの実装は、例外を直接スローすることであることがわかりますが、実際、この方法はオーバーライドするためにアプリケーションに任されています。特定の実装は、実装ロジックに依存します。 DefanyClassを後で説明しましょう。 OK、上記の分析を通じて、次の結論を描くことができます。
独自のクラスローダーを書くときは、親の委任メカニズムに従いたい場合は、FindClassをオーバーライドするだけです。
3。defineclass
まず、defineclassのソースコードを見てみましょう。
defineclass
保護された最終クラス<?
上記のコードから、このメソッドは最終的なものとして定義されていることがわかります。これは、このメソッドをオーバーライドできないことを意味しますファイルは、Java仮想マシン仕様によって指定されたクラスの定義に準拠する必要があります。この方法は、最終的にネイティブメソッドを呼び出して、実際のクラスの負荷を実装します。
わかりました、上記の説明を通して、次の質問について考えてみましょう。
Java.lang.Stringクラスを自分で書いた場合、JDK自体を呼び出すクラスを交換できますか?
答えはノーです。達成することはできません。なぜ?親の委任メカニズムがこの問題を解決するという多くのオンライン説明が見られますが、実際にはあまり正確ではありません。親の委任メカニズムを壊すことができるため、クラスローダーを書いて書いたjava.lang.Stringクラスをロードすることができますが、特にJavaから始まるクラスのためであるため、正常にロードされないことがわかります。 JVM実装により、BootStrpがロードする必要があることが保証されています。
「親委任メカニズム」に従わないシナリオ
上記の委任メカニズムは、主に異なるクラスローダー間でロードされるクラスの相互作用の問題を実現することです。 Javaの親クラスローダー。この状況の発生について話しましょう。
JavaにはJDBC、JNDIなどのSPIライブラリを使用するSPI(サービスプロバイダーインターフェイス)標準があります。JDBCは第三者が提供するドライバーを必要とし、ドライバーJarパッケージがアプリケーション自体に配置されていることを知っています。 ClassPathとJDBCのAPIは、JDKの提供の一部であり、Bootstrpによってロードされています。 Javaは、スレッドクラスのローダーの概念を導入しますドライバー、スレッドのコンテキストクラスローダーを介してロードしても大丈夫です。
さらに、より柔軟なクラスローダーOSGIと一部のJavaアプリサーバーを実装するために、親の委任メカニズムも破損します。