Tomcat は親の委任メカニズムを破壊して Web アプリケーションの分離を実現します。

Tomcat は親の委任メカニズムを破壊して Web アプリケーションの分離を実現します。

Tomcat は、カスタム クラス ローダー WebAppClassLoader を通じて親の委任を解除します。つまり、JVM クラス ローダー ClassLoader の findClass メソッドと loadClass メソッドを書き換えて、Web アプリケーション ディレクトリ内のクラスのロードを優先します。

Tomcat は、サーブレット クラスと、サーブレットが依存する JAR パッケージをロードする役割を担います。 Tomcat 自体も Java プログラムなので、独自のクラスと依存する JAR パッケージをロードする必要があります。

Tomcat 上で 2 つの Web アプリケーションを実行し、それらのアプリケーションに同じ名前で機能が異なるサーブレットがある場合、Tomcat は、競合が発生しないように、同じ名前のこれらの 2 つのサーブレット クラスを同時にロードして管理する必要があります。したがって、Webアプリケーション間のクラスは分離する必要がある。

2 つの Web アプリケーションが両方とも Spring などの同じサードパーティ jar に依存している場合、Spring jar がメモリにロードされた後、Tomcat は 2 つの Web アプリケーションがそれを共有できること、つまり Spring jar が 1 回だけロードされることを保証する必要があります。そうしないと、サードパーティ jar の数が増えるにつれて、JVM のメモリが大きくなりすぎます。
そのため、JVM と同様に、Tomcat 自体のクラスと Web アプリケーションのクラスを分離する必要があります。

Tomcat クラスローダー階層

Tomcat のクラスローダー階層

最初の 3 つはクラス名ではなく、ローダー インスタンス名です。

WebAppクラスローダー

JVM のデフォルトの AppClassLoader を使用して Web アプリケーションをロードする場合、AppClassLoader は 1 つの Servlet クラスのみをロードできます。同じ名前の 2 番目の Servlet クラスをロードする場合、AppClassLoader は最初の Servlet クラスの Class インスタンスを返します。
AppClassLoader の観点からは、同じ名前の Servlet クラスは 1 回しかロードできないためです。

そのため、Tomcat はクラス ローダーWebAppClassLoaderをカスタマイズし、各 Web アプリケーションに対してWebAppClassLoaderインスタンスを作成します。

各 Web アプリケーションの独自の Java クラスと依存する JAR パッケージは、それぞれWEB-INF/classesWEB-INF/libディレクトリに配置され、すべて WebAppClassLoader によってロードされます。

Context コンテナ コンポーネントは Web アプリケーションに対応します。したがって、各 Context コンテナは WebAppClassLoader ローダー インスタンスを作成して維持します。
異なるローダー インスタンスによってロードされたクラスは、クラス名が同じであっても、異なるクラスと見なされます。これは、JVM 内に相互に分離された Java クラス空間を作成することと同じです。各 Web アプリケーションには独自のクラス空間があり、Web アプリケーションは独自のクラス ローダーによって互いに分離されています。

共有クラスローダー

2 つの Web アプリケーションがライブラリ クラスを共有し、同じクラスを繰り返しロードしないようにするにはどうすればよいですか?

親委任メカニズムの各子ローダーは親ローダーを介してクラスをロードできるため、共有するクラスを親ローダーのロード パスに配置することを検討してください。

これは、アプリケーションが JRE コア クラスを共有する方法です。
Tomcat は、Web アプリケーション間で共有されるクラスをロードするために、WebAppClassLoader の親ローダーとしてクラス ローダー SharedClassLoader を作成しました。

WebAppClassLoader がクラスをロードしない場合は、親ローダー SharedClassLoader にクラスのロードを委託します。SharedClassLoader は指定されたディレクトリに共有クラスをロードし、それを WebAppClassLoader に返して共有の問題を解決します。

カタリナクラスローダー

Tomcat 独自のクラスを Web アプリケーションのクラスから分離するにはどうすればよいですか?

兄弟関係: 2 つのクラス ローダーは並列です。親ローダーは同じである場合もありますが、2 つの兄弟クラス ローダーによってロードされるクラスは分離されています。

そのため、Tomcat は Tomcat 独自のクラスをロードするために CatalinaClassLoader を作成しました。

問題は、Tomcat とさまざまな Web アプリケーション間でいくつかのクラスを共有する必要がある場合にはどうすればよいかということです。

共通クラスローダー

共有は依然として父と息子の関係に依存しています。
CatalinaClassLoader と SharedClassLoader の親ローダーとして別の CommonClassLoader を追加します。

CommonClassLoader がロードできるクラスは CatalinaClassLoader と SharedClassLoader で使用できますが、CatalinaClassLoader と SharedClassLoader がロードできるクラスは互いに分離されています。 WebAppClassLoader は SharedClassLoader によってロードされたクラスを使用できますが、各 WebAppClassLoader インスタンスは互いに分離されています。

バネ荷重の問題

デフォルトでは、クラスがクラス ローダー A によってロードされると、そのクラスの依存クラスも同じクラス ローダーによってロードされます。
たとえば、Bean ファクトリとしての Spring は、ビジネス クラスのインスタンスを作成し、ビジネス クラスのインスタンスを作成する前にこれらのクラスをロードする必要があります。 Spring は Class.forName を呼び出してビジネス クラスをロードします。forName のソース コードを見てみましょう。

パブリック静的クラス<?> forName(String className) {
    クラス<?> 呼び出し元 = Reflection.getCallerClass();
    forName0(className, true, ClassLoader.getClassLoader(caller), caller) を返します。
}

呼び出し元である Spring のローダーは、ビジネス クラスをロードするために使用されます。

Web アプリケーション間で共有される JAR ファイルは、繰り返しの読み込みを回避するために SharedClassLoader によって読み込むことができます。共有サードパーティ jar として、Spring は SharedClassLoader によってロードされます。Spring はビジネス クラスもロードする必要があります。前のルールによると、Spring をロードするクラス ローダーはビジネス クラスのロードにも使用されます。ただし、ビジネス クラスは Web アプリケーション ディレクトリにあり、SharedClassLoader のロード パスにはありません。どうすればよいでしょうか。

スレッドコンテキストローダー

そのため、スレッド コンテキスト ローダー、クラス ローダー転送メカニズムが存在します。クラスローダーはスレッドのプライベートデータに格納されるため、同一スレッドであれば、一度スレッドコンテキストローダーを設定すれば、以降のスレッド実行時にクラスローダーを取り出して使用することができます。そこで、Tomcat は Web アプリケーションごとに WebAppClassLoader クラスローダーを作成し、Web アプリケーションを起動するスレッドにスレッドコンテキストローダーを設定します。このようにして、Spring は起動時にスレッドコンテキストローダーを取り出して Bean をロードします。 Spring スレッド コンテキストのロードのコードは次のとおりです。

cl = Thread.currentThread().getContextClassLoader();

StandardContext の起動メソッドでは、現在のスレッドのコンテキスト ローダーが WebAppClassLoader に設定されます。

開始メソッドの終了時に、スレッドのコンテキスト ローダーが復元されます。

Thread.currentThread().setContextClassLoader(originalClassLoader);

これはなぜでしょうか?

スレッド コンテキスト ローダーは、実際にはスレッドのプライベート データであり、スレッドにバインドされています。スレッドがコンテキスト コンポーネントの開始を完了すると、スレッド プールにリサイクルされ、他の処理に使用されます。他の処理に影響を与えないようにするには、以前のスレッド コンテキスト ローダーを復元する必要があります。
Web アプリケーション クラスの読み込みを優先し、読み込みが完了したら元のクラスに戻します。

スレッド コンテキスト ローダーは、JDBC ドライバーなどの特定のブリッジ クラスをロードするためのサブクラス ローダーを指定します。

要約する

Tomcat Context コンポーネントは、Web アプリケーションごとに WebAppClassLoader クラス ローダーを作成します。異なるクラス ローダー インスタンスによってロードされたクラスは互いに分離されるため、Web アプリケーションを分離するという目的が達成されます。同時に、サードパーティの JAR パッケージは、CommonClassLoader などの親ローダーを通じて共有されます。共有サードパーティ JAR パッケージは、特定の Web アプリケーションのクラスをどのようにロードしますか?これは、スレッド コンテキスト ローダーを設定することで解決できます。

複数のアプリケーションで共有される Java クラス ファイルと JAR パッケージは、Web コンテナによって指定された共有ディレクトリに配置されます。

共通クラスローダー
<Tomcat>/common/*に相当します

カタリナクラスローダー
<Tomcat >/server/*に相当します

共有クラスローダー
<Tomcat >/shared/*に相当します

WebAppクラスローダー
<Tomcat >/webapps/<app>/WEB-INF/*に相当します。

Tomcat conf ディレクトリの Catalina.properties ファイルで、さまざまなクラス ローダーの読み込みパスを設定できます。

ClassNotFound エラーが発生した場合は、クラスローダーが正しいことを確認する必要があります。
スレッド コンテキスト ローダーは、Tomcat および Spring のクラス読み込みシナリオで使用できるだけでなく、コア フレームワーク クラスが特定の実装クラスを読み込む必要がある場合にも使用できます。たとえば、よく知られている JDBC は、コンテキスト クラス ローダーを通じてさまざまなデータベース ドライバーを読み込みます。

Tomcat が親の委任メカニズムを破って分離された Web アプリケーションを実現する方法について説明したこの記事はこれで終わりです。Tomcat の分離された Web アプリケーションに関するより関連性の高いコンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Tomcat プロセスの CPU 使用率が高い場合の解決策
  • SpringBootは組み込みTomcat実装手順を開始します
  • Tomcatが親の委任メカニズムを破壊する方法についての簡単な説明
  • Tomcatを使用して共有ライブラリを設定し、同じjarを共有する
  • Tomcat の面接の質問が 15 問も出る、滅多にない機会です!

<<:  JavaScript 文字列の一般的なメソッドの詳細な説明

>>:  ウェブページの読み込み速度を上げる6つのヒント

推薦する

JavaScript サンドボックスの探索

目次1. シナリオ2. サンドボックスの基本機能3. iframeの実装4. Webワーカーの実装5...

MySQL 8.0.16 winx64 のインストールと設定方法のグラフィックチュートリアル

最近、データベースについて学び始めました。最初にやったことは、データベースとは何か、データベースとデ...

要素 el-table テーブルの二次カプセル化 (テーブルの高さの調整付き)

序文会社でのインターンシップ中、フロントエンド開発にはvue+element-uiフレームワークを使...

ウェブページの色特性の分類

色特性の分類あらゆる色は、赤、緑、青の三原色から構成されます。三原色の中で暖色なのは赤だけなので、作...

フロア効果を実現するためのJavaScript

この記事では、フロア効果を実現するためのJavaScriptの具体的なコードを参考までに紹介します。...

MySQL 8.0.23 のインストールと設定方法のグラフィックチュートリアル (Win10 の場合)

この記事では、MySQL 8.0.23のインストールと設定方法を参考までに紹介します。具体的な内容は...

Tomcat+Mysql の高同時実行構成の最適化の説明

1.Tomcatの最適化構成(1)Tomcatのcatalina.batを変更するJavaをサーバー...

Nginx での SSL 証明書のインストールと展開手順の概要

目次問題の説明:インストール手順1. 準備2. サーバーにリモート接続する3. 証明書と秘密鍵ファイ...

WeChatアプレットはウォーターフォールフローのページングスクロール読み込みを実装します

この記事では、WeChatアプレットのウォーターフォールフローページングスクロールロードを実装するた...

Windows での mysql-5.7.28 のダウンロード、インストール、および構成に関する詳細なグラフィックとテキストのチュートリアル

最近MySQLデータベースのバージョンを変更する必要があり、それを記録するために記事を書きます1. ...

意外と知らないJSのループ速度テストのいろいろを徹底解説

目次序文1. forループ2. whileループとdo-whileループ3. forEach、map...

MySQLの文字セット設定を5分で理解しましょう

目次1. コンテンツの概要2. 文字セットと文字順序の概念と関係3. MySQL でサポートされてい...

dockerを使用してGrafana+Prometheus構成をデプロイする

docker-compose-monitor.yml バージョン: '2' ネットワ...

JSプロトタイプとプロトタイプチェーンについての簡単な説明

目次1. プロトタイプ2. プロトタイプポインタ: __proto__要約する1. プロトタイプJa...

CSS を使用してマウスをホバーすることで他のタグのスタイルを変更するサンプルコード

序文:私の知る限り、現在 CSS で制御できるのは、タグをホバーしたときにそのタグの下の兄弟タグとサ...