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 について話す

推薦する

5分でDockerを使ってRedisのクラスターモードとセンチネルモードを構築する方法を教えます

目次1. 準備Redisイメージを取得する2. Redis Sentinel マスタースレーブモード...

dockerでrabbitmqをインストールすると管理ページに入れなくなる問題

1. 環境整備Tencent Cloud Server CENTOS 7 バージョンDockerコン...

vuex での mapState の考え方の応用

目次1. マップ方式2. 応用背景:需要開発プロセス中に、一部のインターフェースは、ページに表示する...

Angularコンポーネントの仲介モードの詳細な説明

目次1. 仲介業者モデル2. 例1. 見積コンポーネントに購入ボタンを追加する2. 親コンポーネント...

Nginx で何ができるかの包括的な分析

序文この記事は、サードパーティのモジュールをロードせずにNginxで処理できることのみに焦点を当てて...

現在のマウススライドの座標を取得するVue+openlayer5メソッド

序文: Vue プロジェクトで現在のマウスの座標を取得するにはどうすればよいでしょうか。ここで共有す...

面接の質問: 3 行 3 列のレイアウト、表は結合され、ネストされた表は許可されません

面接の質問で、3 行 3 列のレイアウトが求められます。1 行目の 2 番目の列と 2 行目の 2 ...

SSMは、mysqlデータベースアカウントのパスワード暗号文ログイン機能を実装します。

導入当社は、情報セキュリティと機密アプリケーションに関わるいくつかのプロジェクトの研究開発に従事して...

Linuxの相対パスと絶対パスの使用

01. 概要絶対パスと相対パスはシェル環境でよく使用され、それぞれに独自の用途があります。相対パスの...

モバイル端末におけるビューポートの具体的な使用法についての簡単な説明

目次1. 基本概念1.1 2種類のピクセル1.2 3つのビューポート2. ビューポート設定3. 1回...

WeChatミニプログラムをTencent Mapsに接続する2つの方法

最近、WeChat アプレットを作成しているのですが、いくつか問題が発生しました。インターネットでい...

docker を使用して hbase をデプロイする方法

スタンドアロンの hbase について、まずは説明しましょう。 Dockerをインストールするまず ...

W3C チュートリアル (10): W3C XQuery アクティビティ

XQuery は、XML ドキュメントからデータを抽出するための言語です。 XQuery は、XML...