ホームページ  >  記事  >  Java  >  Java ローダーについての深い理解

Java ローダーについての深い理解

王林
王林転載
2019-11-29 13:44:292468ブラウズ

Java ローダーについての深い理解

1. クラスとクラス ローダー

クラス ローダー: クラスの完全修飾名による読み込みフェーズの最初のステップです。このクラスのバイナリ バイト ストリームを jvm にロードします。

クラスとクラス ローダー: クラスの一意性は、クラス自体と、それをロードするクラス ローダーによって決まります。2 つのクラスが等しいかどうかは、それらが同じクラス ローダーによってロードされるという前提によって決まります。

jvm 仮想マシンには 2 つのクラス ローダーが含まれています。1 つは C で実装された起動クラス ローダー (Bootstrap ClassLoader)、もう 1 つはその他すべて Java クラス ローダーで実装されています。

Java プログラムの観点から:

1) クラス ローダーを開始します: \lib ディレクトリまたは -Xbootclasspath パラメータで指定されたパスにクラスをロードします。必要なファイルに加えて、名前は仮想マシンによって認識されますが、jvm によって認識されない場合はロードできません。

2) 拡張クラス ローダー: \lib\exit ディレクトリまたは java.exit.dirs システム変数で指定されたパスにあるすべてのクラス ライブラリをロードします。

3) アプリケーションクラスローダ(システムクラスローダ):クラスローダのgetSystemClassloader()メソッドの戻り値です。ユーザー クラス パスで指定されたクラス ライブラリのロードを担当します。アプリケーションにカスタム クラス ローダーがない場合、これがプログラムのデフォルトのクラス ローダーになります。

無料のオンライン ビデオ教育: Java ビデオ チュートリアル

2. 保護者委任モデル

Java ローダーについての深い理解

##最上位の起動クラス ローダーを除き、他のすべてのクラス ローダーには独自の親クラス ローダーがあります。親子関係は継承によって実装されるのではなく、親クラス ローダーを再利用するための組み合わせ関係によって実装されます。

作業プロセス: クラス ローダーはクラス ロード リクエストを受信します –> リクエストを親クラス ローダーに委任します (トップレベルのクラス ローダーが開始されるまで) –> 親クラスはロードを試みます、そして読み込みの失敗は子クラス ローダーにフィードバックされます –> サブクラス ローダーは

親委任モデルの利点: Java の基礎となる API の安定性を確保し、カスタムの読み込みによって生じる複数の違いを回避します基本クラスと同じ名前のクラス (Object) が存在するため、Java の基本的な動作に混乱が生じます。

親委任モデルのソース コード:

メソッドは、スレッドの安全性を確保するために同期ロックを追加します。まず、クラスがロードされているかどうかを確認します。ロードされていない場合は、親を呼び出しますクラスローダー.loadClass() メソッドで、親クラスローダーが空の場合、それは起動クラスローダーを意味し、起動クラスローダーが呼び出されます。

親クラスのロードに失敗した場合は、ClassNotFoundException がスローされ、独自の findClass() メソッドを呼び出して親クラスをロードします。

protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
{
    //同步锁
    synchronized (getClassLoadingLock(name)) {
        // 首先检车这个类是不是已被加载
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                if (parent != null) {
                    //如果父类不为空则调用父类加载器的loadClass方法
                    c = parent.loadClass(name, false);
                } else {
                    //没有父类则默认调用启动类加载器加载
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                //如果父类加载器找不到这个类则抛出ClassNotFoundException
            }


            if (c == null) {
                // 父类加载器失败时调用自身的findClass方法加载
                long t1 = System.nanoTime();
                c = findClass(name);


                //记录
                sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();
            }
        }
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }
}

3. 親委任モデルの破棄

1. 親委任モデルの最初の破棄

が表示されました。 JDK1.2以降では、クラスローダと抽象クラスjava.lang.ClassLoaderがすでに存在していました。

したがって、上位互換性を確保するために、JDK1.2 以降、新しい保護されたメソッド findClass が ClassLoader に追加されました。ユーザーは、loadClass メソッドをオーバーライドするのではなく、独自のクラス ロード ロジックを findClass メソッドに記述して、カスタム クラスのロードが親委任モデルに準拠していることを確認します。

2. 2 番目の破壊

モデル自体に欠陥があります。親の委任により、各クラス ローダーの基本クラスを確実に統合できます。これは、ユーザー コードが基本クラスを呼び出すときです。基本クラスがユーザー コードをコールバックする場合には適用されません。たとえば、SPI が関係するシナリオでは、必要な SPI コードをロードします。

SPI メカニズムの概要については、他の記事を参照してください。

この問題を解決するために、スレッド コンテキスト ローダー (Thread Context ClassLoader) が導入されました。このクラス ローダーは、java.lang.Thread クラスの setContextClassLoader() メソッドを通じて設定できます。設定は親スレッドから継承されます。グローバルに何も存在しない場合、デフォルトはアプリケーション クラス ローダーです。このローダーは、子クラス ローダーにロードを要求する親クラス ローダーのアクションを完了するために使用できます。

3. 3 番目の被害

# は、ホット デプロイメント、ホット リプレースなどのプログラム ダイナミクスの追求によって引き起こされます。

たとえば、モジュラー標準 OSGi R4.2 では、親の委任のツリー構造がより複雑なネットワーク構造に変更されました。

推奨される Java 記事チュートリアル: Java 入門チュートリアル

以上がJava ローダーについての深い理解の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcsdn.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。