Tomcat での jar のロードに関する異常な問題の分析と解決

Tomcat での jar のロードに関する異常な問題の分析と解決

現象の説明:

プロジェクトでは、Springboot を使用して Web プロジェクトを開始します。起動フェーズ中に、コンソールに例外が表示されました: 「1.10.3-1.4.3\hdf5.jar システムは指定されたファイルを見つけることができません。」 これらの例外はプロジェクトの正常な動作には影響しませんが、厳格な技術者として、これらの例外を見ることは敵を見るのと同じであり、できるだけ早く排除する必要があります。

java.io.FileNotFoundException: D:\.m2\repository\org\bytedeco\javacpp-presets\hdf5-platform\1.10.3-1.4.3\hdf5.jar (指定されたファイルが見つかりません。)
 java.util.zip.ZipFile.open(ネイティブメソッド)
 java.util.zip.ZipFile.<init>(ZipFile.java:225) で
 java.util.zip.ZipFile.<init>(ZipFile.java:155) で
 java.util.jar.JarFile.<init>(JarFile.java:166) で
 java.util.jar.JarFile.<init>(JarFile.java:130) で
 org.apache.tomcat.util.compat.JreCompat.jarFileNewInstance(JreCompat.java:188) で
 org.apache.tomcat.util.scan.JarFileUrlJar.<init>(JarFileUrlJar.java:65) で
 org.apache.tomcat.util.scan.JarFactory.newInstance(JarFactory.java:49) で
 org.apache.tomcat.util.scan.StandardJarScanner.process(StandardJarScanner.java:374) で
 org.apache.tomcat.util.scan.StandardJarScanner.processURLs(StandardJarScanner.java:309) で
 org.apache.tomcat.util.scan.StandardJarScanner.doScanClassPath(StandardJarScanner.java:266) で
 org.apache.tomcat.util.scan.StandardJarScanner.scan(StandardJarScanner.java:229) で
 org.apache.jasper.servlet.TldScanner.scanJars(TldScanner.java:262) で
 org.apache.jasper.servlet.TldScanner.scan(TldScanner.java:104) で
 org.apache.jasper.servlet.JasperInitializer.onStartup(JasperInitializer.java:101) で
 org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5204) で
 org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) で
 org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1421) で
 org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1411) で
 java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) で
 java.util.concurrent.FutureTask.run(FutureTask.java) で
 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) で
 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) で
 java.lang.Thread.run(Thread.java:748) で

2019-03-29 18:09:08.303 警告 16940 --- [ost-startStop-1] oatomcat.util.scan.StandardJarScanner: クラスローダー階層から [file:/D:/.m2/repository/org/bytedeco/javacpp-presets/hdf5-platform/1.10.3-1.4.3/hdf5-linux-x86.jar] をスキャンできませんでした

java.io.FileNotFoundException: D:\.m2\repository\org\bytedeco\javacpp-presets\hdf5-platform\1.10.3-1.4.3\hdf5-linux-x86.jar (指定されたファイルが見つかりません。)
......
2019-03-29 18:09:08.578 警告 16940 --- [ost-startStop-1] oatomcat.util.scan.StandardJarScanner: クラスローダー階層から [file:/D:/.m2/repository/org/bytedeco/javacpp-presets/hdf5-platform/1.10.3-1.4.3/hdf5-linux-x86_64.jar] をスキャンできませんでした

java.io.FileNotFoundException: D:\.m2\repository\org\bytedeco\javacpp-presets\hdf5-platform\1.10.3-1.4.3\hdf5-linux-x86_64.jar (システムは指定されたファイルを見つけることができません。)

プロジェクト環境の説明

  • tomcat: springboot 組み込みバージョン 8.5.29 を使用する
  • Maven による依存関係管理
  • Spring Bootのバージョンは2.0.1です
  • Springフレームワークのバージョンは5.0.5です
  • このプロジェクトは、Deep Learn 4 Java (優れたJava機械学習ライブラリ) を参照しています。
 <依存関係>
 <groupId>org.deeplearning4j</groupId>
 <artifactId>ディープラーニング4j-コア</artifactId>
 <バージョン>1.0.0-beta3</バージョン>
 </依存関係>

問題のある jar 依存関係

追跡分析

エラーは起動フェーズで報告されるため、起動クラスを見つけてブレークポイントを追加し、どの段階でエラーが報告されているかを段階的に追跡し、エラーの原因を分析します。 Springboot コードをトレースしてデバッグし、jar の読み込み場所を見つけました。主なクラスとメソッドは次のとおりです。

追跡クラス org.apache.tomcat.util.scan.StandardJarScanner

メソッド doScanClassPath(...)

このメソッドは、すべてのクラスローダーをトラバースし、各クラスローダーに jar パッケージをロードします。

上記のアイコンの赤い部分はキーコードで、変数 classPathUrlsToProcess には、ロードするすべての jar 情報、主に jar パッケージのパス情報が格納されます。これは、Maven で見た jar パッケージと同じであることがわかります。

  • メソッド processURLs(...)

このメソッドは、現在のクラスローダーのすべての jar、つまり classPathUrlsToProcess に対してスタック操作を実行し、各 jar パッケージを処理します。キーコードは以下の通りです。

  • メソッド process()

このメソッドは、各jarを読み込んで分析し、

プロセスマニフェスト(jar、isWebapp、classPathUrlsToProcess) 

  • メソッド processManifest

このメソッドは、jar 内のマニフェスト ファイルを処理し、マニフェスト ファイル内のクラス パスを分離し、そのコンテンツを新しい依存 jar として classPathUrlsToProcess に挿入します (processURLs メソッドは、スタック結果に jar をロードします)。

原因分析

実際、問題はマニフェスト ファイルのクラスパスにあります。コードを分析すると、Tomcat は Maven によって管理される jar パッケージをロードするだけでなく、jar 内のマニフェスト ファイルも分析することがわかります。クラスパスがある場合は、その中のコンテンツも jar パッケージの依存関係に追加され、これらの jar パッケージがロードされます。

エラーが発生する場所を確認するために、例として hdf5-1.10.3-1.4.3.jar のマニフェスト ファイルを開きます。

ここでの jar パッケージにはパスもバージョン番号もないため、Tomcat は hdf5-1.10.3-1.4.3.jar のパスに従ってそれをロードすることに注意してください。

ただし、これらの jar はプロジェクト内の対応する場所に存在しないため、jar が見つからないという例外が発生します。実際、プロジェクトにはこれらの jar がありますが、パスと名前は異なります。上の図の左側では、これらの jar がすでに Maven で使用可能であることがわかりますが、名前の後にはバージョン番号が追加されており、パスはそれぞれの Maven リポジトリ内にあります。

この時点で問題の原因がわかったので、次にその解決方法を考えてみましょう。

解決

オプション1:

存在しない jar パッケージがロードされないようにするには、マニフェスト内のクラスパスを削除するか、マニフェスト ファイルを削除します。ただし、Maven が更新されるたびに変更が上書きされ、例外が再度発生する可能性があります。

オプション2:

ロードによって要求されたパスに従って、対応する jar パッケージをコピーし、名前を変更してバージョン番号を削除しますが、これにより jar の冗長性が発生し、同じ jar が 2 回ロードされることになります。

オプション3:

Tomcat バージョンを 8.5.0 以前にダウングレードします。バージョン 8.5.0 では、マニフェストは分析およびロードされないため、例外は発生しません。

オプション4

マニフェスト ファイルをスキャンしないようにコード設定を追加します。

 @ビーン
 パブリックTomcatServletWebServerFactory tomcatFactory() {
  新しいTomcatServletWebServerFactory()を返す{
   @オーバーライド
   保護されたvoid postProcessContext(コンテキストコンテキスト) {
    ((StandardJarScanner) context.getJarScanner()).setScanManifest(false);
   }
  };
 } 

要約:

以上がこの記事の全内容です。この記事の内容が皆様の勉強や仕事に何らかの参考学習価値をもたらすことを願います。123WORDPRESS.COM をご愛顧いただき、誠にありがとうございます。

以下もご興味があるかもしれません:
  • Tomcat クラスローダーの実装方法とサンプルコード
  • Tomcat を起動したときに Eclipse が Web プロジェクトをロードできない問題を解決する
  • Tomcatのホットデプロイメントとホットロード方式の詳細な説明
  • Tomcat が CSS や JS などの静的リソース ファイルをロードできない場合の解決策
  • Java tomcat のクラスローダーとセキュリティメカニズムをご存知ですか?

<<:  mysql 5.7.20 win64 のインストールと設定方法

>>:  Vue の nextTick について話す

推薦する

MySQLが基礎データ構造としてB+ツリーを使用する理由

MySQL の基盤となるデータ構造が B+ ツリーであることは誰もが知っていますが、ではなぜ赤黒ツリ...

GolangでMySQLデータベースのバックアップを実装する方法

背景Navicat は、最高の MySQL 視覚化ツールです。ただし、ビューのインポートとエクスポー...

HTML で JavaScript を使用する

<script> タグHTML5では、スクリプトには次の属性があります: async、d...

mysql binlog (バイナリログ) を表示する方法

たとえば、新しいテーブルを作成したり、既存のテーブルのデータを更新したりすると、これらのイベントは、...

MySQL設定ファイルを変更できない問題の解決方法(Win10)

他の人のために解決した問題を記録します。問題の説明MySQLのバージョンは5.7、オペレーティングシ...

XHTML チュートリアル: Transitional と Strict の違い

実際、XHTML 1.0 は、Transitional DOCTYPE と Strict DOCTY...

MySQLとOracleの違いを簡単に説明してください

1. Oracle は大規模データベースですが、MySQL は小規模から中規模のデータベースです。O...

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

目次Tomcat クラスローダー階層WebAppクラスローダー共有クラスローダーカタリナクラスローダ...

jsはシンプルな英語-中国語辞書を実装します

この記事では、参考までに、簡単な英中辞典を実装するためのjsの具体的なコードを紹介します。具体的な内...

Tomcat の設定と Eclipse での起動方法

目次Tomcat8のインストールと設定方法tomcat ダウンロードTomcat マネージャーを有効...

Nginx+SSL による双方向認証を実装するためのサンプル コード

まずディレクトリを作成する cd /etc/nginx mkdir ssl cd ssl CA と自...

MySQL は ACID トランザクションをどのように実装しますか?

序文最近、面接中に、MySQL の InnoDB エンジンがどのようにトランザクションを実装している...

MYSQL ストアドプロシージャと関数の簡単な記述

ストアドプロシージャとは簡単に言えば、これは強力で、JAVA 言語のメソッドに似た比較的複雑な論理関...

CSSレコードテキストアイコン配置のいくつかのソリューション

開発中に画像とテキストが 1 行に表示されることはよくあります。2 つのインライン要素を揃えるのは通...

高品質なウェブページのデザイン方法 高品質なウェブページ(画像とテキスト)のデザイン経験

オープンプラットフォームの増加に伴い、そこから派生するさまざまなアプリケーションサービスも増加傾向に...