負荷クラス:あなたは私の心を知っていれば、おそらく、このようなミスを犯していないだろう

序文

クラスがロードされると、コンテキストのか、豆内部のスプリングが良い記録を持っていない可能性があるので、数日前にjava.lang.ExceptionInInitializerErrorオンライン散発的な例外は、調査があります。次に、我々は同様のミスを犯し、次回を回避するために、クラスローディング機構を理解し、心のクラスにロードされ、この問題を通り抜けました。

異常なアナログ再生

コードは以下の通りであります:

public class SMSNotifyUtils {
     private  static SMSNotifyService service = ContextProviderUtils.getBean("smsNotifyService", SMSNotifyService.class);
 }
 
 public class ContextProviderUtils implements ApplicationContextAware {

    private static ApplicationContext appContext;

    @SuppressWarnings("unchecked")
    public static <T> T getBean(String beanName, Class<T> clazz) {
        if (appContext == null) {
            System.out.println("null appContext");
        }
        return (T) appContext.getBean(beanName, clazz);
    }

    public void setApplicationContext(ApplicationContext appContext) throws BeansException {
        ContextProviderUtils.appContext = appContext;
    }
}
复制代码

上記のコードは、静的変数を初期化するために、スプリングから豆容器を得ます。あなたは何かが間違っていると思いますか?それは、静的変数の初期化をトリガーするときを考えてみて?クラスのロードプロセス?私は春のコンテナBeanに取得することができますか?コンテナの起動が完了していますか?

次のように実行します。

次のように:

  • ログから取得することができ、nullポインタ例外が、明らかに春のコンテキストまたはBean内ではうまくヒットしなかった、それが割り当てる必要があり、それは確かに例外レポートです。どのようにこの問題を解決するには?

  • 開始についてスプリングもので、春の豆の容器と、新しいClassPathXmlApplicationContextが完了を実行し、それをプープー。

  • まあ関連のクラスのロードとあまりにも静的変数、クラス変数と呼ばれる静的変数の別名。トリガークラスのロードには、事を初期化するためにそれを与えるだろう。

  • コンテキスト/スプリングビーン最初のステップのばねよりSMSNotifyUtilsクラス荷重:上記の問題は、より深く行く、それは次のように理解することができます。OK、我々は彼女の心の中に、それを確認するために、クラスローディング機構の波を指示します。

クラスローディングの心

まず、クラスローディング機構

仮想マシンのタイプのデータをメモリからロードするクラスファイルに記述され、そしてデータ、解析および変換の初期化を確認します。最終的にプロセスのほとんどの種類が直接仮想マシンで使用できるJavaクラスローディング機構は、仮想マシンです。

JVMクラスローダーのメカニズムは、主に次の3種類があります。

  • 以下のための全体的な責任:クラスローダがクラスをロードするための責任がある場合には、いわゆる全体的な責任は、クラスによって異なり、また、それがロードする別のクラスローダの使用から表示されないかぎり、このクラスローダは、ロードを担当し、他のクラスへの参照になります。

  • 両親の委任:いわゆる両親の代理人は、親クラスローダは、クラスがクラスが独自のクラスパスからロードすることはできませんロードしようとしたときにのみ、親クラスローダに、クラスをロードしようとするようにすることです。人気話す、親クラスローダは、タスクが正常に戻る完全にロードできる場合は、クラスをロードするために、特定のクラスローダで、要求に応じて、最初のタスクは、ターン再帰では、親ローダー負荷に委託されます。唯一の父ローダは、このタスクの負荷を完了できない場合、それ自体をロードします。

  • :キャッシュメカニズムメカニズムをキャッシュするとき、クラスの検索では、バッファゾーンからまず、プログラムはクラスの使用を必要とするとき、クラスのすべてが、キャッシュによってロードされることをクラスローダを確保し、クラスオブジェクト内のキャッシュ領域が存在しない場合にのみ、システムは、クラスに対応するバイナリデータを読み出し、バッファに格納されたクラスオブジェクトに変換します。これは、クラスを変更した後、あなたは、その理由のJVMを再起動して有効にするプログラムを変更する必要があります

ライフサイクルの第2、タイプ

ロード

ロード・ステージは、クラスローディングプロセスです。ロード・フェーズでは、仮想マシンは、次の3つのことを完了するために、主に次のとおりです。

  • クラスの完全修飾名で定義されたバイナリバイトストリームを取得するには
  • これは、ランタイムデータ構造領域法に静的記憶構造のバイトストリームを表します
  • メモリ内の発生は、このクラスの様々なデータ領域へのアクセスエントリのための方法として、このクラスのjava.lang.Classオブジェクトを表します

ロード・ソース

クラスローダは、通常、クラスがロードされ、「最初の使用」クラスまで待つ必要はありません、Java仮想マシン仕様は、システムがいくつかのクラスを事前にロードすることができます。

ロード機会

  • クラスが初期化されていない場合は、このバイトコード命令は、初期化がそれをトリガーするために必要とされる新しい、getstatic、putstatic invokestaticまたは4に遭遇します。読み取りまたはクラス(最終修正の静的フィールドを設定するときにオブジェクトをインスタンス化する新しいキーワードを使用して、結果は静的の定数プールにコンパイルされています:これは、Javaコードがされ、最も一般的なシナリオの4つの命令を生成し、ときフィールド)を除いて、だけでなく、授業時間の静的メソッドを呼び出します。
  • クラスが初期化されていない場合は、と呼ばれるクラスを反映するために、パッケージアプローチをjava.lang.reflectで使用するときは、その初期化をトリガーする必要があります。
  • クラスを初期化するとき、あなたが親クラスが初期化されていない見つけた場合、あなたは親クラスの初期化をトリガーする必要があります。
  • 仮想マシンが起動すると、ユーザは、このクラスを初期化するために、仮想マシン(mainメソッドを()が含まれているクラス)を実行するためのメインクラスを指定する必要があります。
  • 最終分析結果REF_getStatic、REF_putStatic、処理するREF_invokeStatic方法がjava.lang.invoke.MethodHandleインスタンス場合は、JDK 1.7の動的言語サポートを使用して、この方法は、対応するクラス初期化されていないを扱うときは、トリガする必要がありますその初期化。

次の図のパフォーマンスにクラスのロード時間:

接続

接続は、検証、準備、分析の段階が含まれます

検証

最初のステップは、接続フェーズを確認することです、この段階の目的は、クラスに含まれる情報のバイトストリームファイルが自分自身の安全を危うくしません、現在の仮想マシンと仮想マシンの要件を満たしていることを確認することです。

レディ

準備フェーズは、公式には、これらの変数は、プロセスに割り当てられたメモリ領域で使用され、初期位相値を設定するクラス変数およびクラス変数にメモリを割り当てることです。

以下のため:パブリックstatic int型値= 123;、0の代わりに123の初期値の準備段階後に、この時間はまだJavaメソッドを開始していない、変数値、123の操作に割り当てられた値は、初期化フェーズ中に実行されます。

解決

ステージを解析すると、直接参照を交換するプロセスへのシンボリック参照の定数プールへの仮想マシンです。

シンボル参照:参照、リテラルシンボルに記載のシンボルの特定のセットへのシンボル参照は、任意の形態であってもよく、限り目標を明確に配置することができるように使用することができます。

直接参照:直接参照は、オブジェクトへの直接ポインタ、相対オフセットまたは間接的にターゲットを処理するために標的化され得ます。

初期化

カテゴリクラス初期化フェーズは、参加からクラスローダによって定義に加えて、上記クラスローディングプロセスをロードする最後のステップであり、残りの動作は完全に負荷段階の間、仮想マシン制御およびユーザ・アプリケーションによって支配されます。初期化フェーズに、実際にプログラムコード(バイトコード)で定義されたJavaクラスを開始しました。以下のような:

private static int a = 10
复制代码

準備段階0に割り当てられたクラスローダでは、初期化フェーズ10に割り当てました。

第三に、クラスローダ

JVM、対応するClassオブジェクトの実行時に変換読み込んだデータバイトコードのクラスファイル。この操作は、クラスローダと呼ばれる、コードモジュールが実行されます。

クラスローダ種

ルートクラスローダ(ブートストラップクラスローダ):このクラスローダは、コアの一部を担当して、JVMのクラスローダは、内の識別されたC ++で実装され、それはJVMと一体となっています。

拡張クラスローダ(拡張クラスローダ):これは、JRE拡張ディレクトリ、クラスのlib / extにまたはシステムプロパティのjava.ext.dirs JARディレクトリパケットによって指定をロードする責任があります。Java言語で実装され、親クラスローダがnullです。

Applicaitonクラスローダ(アプリケーションクラスローダ):私たち自身のカスタム書かれたクラスをロードするために使用

親委譲モデル

クラスローダークラスローダーが要求を受信した場合、それは最初にこのクラスをロードしようとするために所有していませんが、この要求は完了し、親クラスローダに委譲されます。彼らの検索で親ローダーは、指定されたクラス(すなわちClassNotFoundExceptionが)見つからない場合にのみ、各クラスローダが真である、サブローダは、独自のをロードしようとします。

親委任モデルコードの実装

protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
    //1 首先检查类是否被加载
    Class c = findLoadedClass(name);
    if (c == null) {
        try {
            if (parent != null) {
             //2 没有则调用父类加载器的loadClass()方法;
                c = parent.loadClass(name, false);
            } else {
            //3 若父类加载器为空,则默认使用启动类加载器作为父加载器;
                c = findBootstrapClass0(name);
            }
        } catch (ClassNotFoundException e) {
           //4 若父类加载失败,抛出ClassNotFoundException 异常后
            c = findClass(name);
        }
    }
    if (resolve) {
        //5 再调用自己的findClass() 方法。
        resolveClass(c);
    }
    return c;

复制代码

異常な再生復帰

例外コード:

private  static SMSNotifyService service = ContextProviderUtils.getBean("smsNotifyService", SMSNotifyService.class);
复制代码

前のセクションから、我々はクラスローディング機構、負荷のタイミング、ロードプロセスを見直します。まあ、そこにはクラスがロードされたときには見られないいくつかのコード上の問題、春のコンテナやBeanが良いの初期化にはまだできませんを参照して、この時間は確かにこの問題を解決するためにどのようにして、NULLポインタになりますか?

次のように、初期化メソッド内でシンクに

  private static SMSNotifyService service=null;

  public static SMSNotifyService getSMSNotifyService() {
        if (service == null) {
            service = ContextProviderUtils.getBean("smsNotifyService", SMSNotifyService.class);
        }
        return service
 }
复制代码

リファレンスと感謝

個人公開番号

懸念へようこそ、私たちは一緒に議論し、一緒に勉強します。

おすすめ

転載: juejin.im/post/5d85c54a6fb9a06ad16facc0