序文
Spring Boot自体のスタートアップ原則の分析については、http://www.vevb.com/article/141478.htmを参照してください。
Spring BootのClassLoader継承関係は、以下に示されているデモを実行し、さまざまなシナリオで実行できます。さまざまなシナリオでのスプリングブートアプリケーションのクラスローダー継承関係を知ることができます。
https://github.com/hengyunabc/spring-boot-inside/tree/master/demo-classloader-context
3つの状況があります。
IDEでは、Run Main FunctionがSpringのクラスローダーを直接実行します。クラスローダーのURLには、すべての瓶と独自のターゲット/クラスが含まれています
=========スプリングブートアプリケーションクラスローダーURLS ==============
classloader urls:sun.misc.launcher$appclassloader@2a139a55
file:/users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/classes/
file:/users/hengyunabc/.m2/repository/org/springframework/cloud/spring-cloud-starter/1.1.9.release/spring-cloud-starter-1.1.9.release.jar
file:/users/hengyunabc/.m2/repository/org/springframework/boot/spring-boot-starter/1.4.7.release/spring-boot-starter-1.4.7.Release.jar
...
太った瓶として実行します
MVN Clean PackageJava -Jar Target/Demo-ClassLoader-Context-0.0.1-Snapshot.jar
アプリケーションのメイン関数を実行するクラスローダーはLaunchEdurlClassloaderであり、その親はSystemClassLoaderです。
=========クラスローダーツリー==============
org.springframework.boot.loader.launchedurlclassloader@1218025c
-sun.misc.launcher$appclassloader@6bc7c054
-sun.misc.launcher$textclassloader@85ede7b
LaunchedURLClassLoader的urls 、 fat jar BOOT-INF/classes!/ directory、およびすべてのjarがブートインフ/libにあります。
=========スプリングブートアプリケーションクラスローダーURLS ==============
classloader urls:org.springframework.boot.loader.launchedurlclassolasser@1218025c
jar:file:/users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo-classloaser-context-0.0.1-snapshot.jar!/boot-inf/classes!////
jar:file:/users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo-classolasser-context-0.0.1-snapshot.jar!/boot-inf/lib/lib/spring-boot-1.4.7.Release.jar!///////
jar:file:/users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo-classer-context-0.0.0.1-snapshot.jar!/boot-inf/lib/lib/spring-web4.9.9.releease.jar!//////
...
SystemClassLoaderのURLはdemo-classloader-context-0.0.1-SNAPSHOT.jar自体です。
=========システムclassloader urls ==============
classloader urls:sun.misc.launcher$appclassloader@6bc7c054
file:/users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo-classloader-context-0.0.1-snapshot.jar
減圧ディレクトリとして実行します
MVN Clean Packagecd Targetunzip Demo-Classloader-Context-0.0.1-Snapshot.jar -d Democd Demojava org.springframework.boot.loader.propertieslauncher
アプリケーションのメイン関数を実行するクラスローダーはLaunchedURLClassLoaderであり、その親はSystemClassLoaderです。
=========クラスローダーツリー==============
org.springframework.boot.loader.launchedurlclassloader@4aa298b7
-sun.misc.launcher$appclassloader@2a139a55
-sun.misc.launcher$textclassloader@1b6d3586
LaunchedURLClassLoaderのURLは、DecompressionディレクトリのBOOT-INF/classes/および/BOOT-INF/lib/の下のJARパッケージです。
=========スプリングブートアプリケーションクラスローダーURLS ==============
classloader urls:org.springframework.boot.loader.launchedurlclassolasser@4aa298b7
file:/users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo/boot-inf/classes/
jar:file:/users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo/boot-inf/lib/bcpkix-jdk15on-1.55.jar!//
jar:file:/users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo/boot-inf/lib/bcprov-jdk15on-1.55.jar!///
jar:file:/users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo/bootinf/lib/classmate-1.3.3.jar!////
SystemClassLoaderのURLには、現在のディレクトリのみがあります。
=========システムclassloader urls ==============
classloader urls:sun.misc.launcher$appclassloader@2a139a55
file:/users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo/
実際、実行する他の2つの方法があります: mvn spring-boot:runとmvn spring-boot:run -Dfork=trueですが、まれに使用されず、個別に説明しません。興味があるなら、自分で走ることができます。
スプリングブートのクラスローダーの継承関係の概要
メイン関数がIDEで実行される場合、クラスローダーは1つだけです。つまり、SystemClassLoader
ファットジャーとして実行するとき、親がSystemClassLoaderであるLaunchEdurlClassloaderがあります
LaunchEdurlClassloaderのURLは、boot-inf/classesのjarと、脂肪瓶のブートインフ/libです。 SystemClassloaderのURLは、脂肪瓶自体です。
解凍されたディレクトリを実行するとき、それはFat JARに似ていますが、URLはディレクトリの形式です。ディレクトリ形式は、より良い互換性を備えています。
スプリングブートバージョン1.3。および1.4。
スプリングブート1.3。*バージョン
スプリングブートローダークラスはファットジャーに配置されます
スプリングブート1.4のパッケージ構造の変更は、このコミットによって導入されました
https://github.com/spring-projects/spring-boot/commit/87fe0b2adeef85c842c009bfeebac1c84af8a5d7
このコミットの当初の意図は、クラスローダーの継承関係を簡素化し、LaunchEdurlClassloaderを直感的に最初に実装することです。同時に、パッケージング構造は従来のWARパッケージアプリケーションに近いものです。
しかし、この変化は多くの複雑な問題を引き起こしました。上記から、クラスローダーの相続関係を少しめまいに分析しました。
現在のクラスローダー相続関係のいくつかの影響
一部のコードはIDEでうまく実行されているが、実際に展開されたときに機能しないことを発見する可能性のある多くのユーザーがいます。多くの場合、それはクラスローダーの構造によって引き起こされます。ここにいくつかのケースがあります。
demo.jar!/boot-inf/classes!/この方法は、URLが機能しません
Spring Bootは標準のJARプロトコルを拡張し、JARのマルチレイヤージャーとJARのディレクトリをサポートできるためです。 Spring Bootアプリケーションスタートアップ原則の分析を参照してください
Spring Boot 1.3には瓶にJARがありますが、Tomcat8自体がJARのJARをサポートするなど、比較的堅牢なコードがこの状況を処理できます。
ただし、ほとんどのコードはdemo.jar!/BOOT-INF/classes!/などの複数のURLをサポートしていません。したがって、Spring Boot1.4では、多くのライブラリコードが無効になります。
demo.jar!/meta-inf/リソースの下でのリソースの問題
サーブレット3.0仕様では、アプリケーションは静的リソースをMeta-INF/リソースに配置でき、サーブレットコンテナは読み取りをサポートします。しかし、上記の継承結果から、問題を見つけることができます。
これにより、奇妙な現象が生まれます。
さらに、Spring Bootの公式JSSPの例は、戦争のパッケージ形式のみをサポートしており、これも引き起こされるFat Jarをサポートしていません。
GetResource( "")およびgetResources( "")の返品値に関する問題
GetResource( "")のセマンティクスは、クラスローダーURLの最初のURLを返すことです。多くの場合、ユーザーはこれが独自のクラスディレクトリまたはJAR URLであると考えています。
しかし、実際、クラスローダーはURLSリストをロードするため、OSの低レベルの実装に関連するランダムであり、URLの順序が同じであることを保証することはできません。したがって、GetResource( "")によって返される結果はしばしば異なります。
ただし、多くのライブラリまたはアプリケーションは、スキャンリソースを見つけるためにこのコードに依存しているため、Spring Bootで動作しません。
さらに、Spring Bootは3つの異なる形式で実行され、GetResources( "")によって返された結果も異なることに注意してください。ユーザーは、デモのコードを自分で変更して、結果を印刷できます。
要するに、これら2つのAPIに頼らないでください。自分でそれを見つけるためにリソースを配置するのが最善です。または、Spring自体が提供するリソーススキャンメカニズムを直接使用します。
ClassPathに似た野生の分類問題*:** - service.xml
ユーザーには複数のコードモジュールがあり、複数の *-service.xmlスプリング構成ファイルは異なるモジュールの下に配置されます。
ユーザーがclassPath*:** - service.xmlのようなワイルドカードを使用してリソースをロードする場合、IDEで実行するときに正しくロードできる可能性が非常に高いが、脂肪瓶の下にロードすることはできない。
Spring独自のドキュメントから関連する分析を見ることができます。
https://docs.spring.io/spring/docs/4.3.9.Release/javadoc-api/org/springframework/core/support/pathmatchingresourcepatternresolver.html
警告:「ClassPath:」とANTスタイルのパターンと組み合わせると、実際のターゲットファイルがファイルシステムに存在しない限り、パターンが開始される前に少なくとも1つのルートディレクトリでのみ確実に機能することに注意してください。これは、「classpath:*。xml」のようなパターンは、JARファイルのルートからファイルを取得するのではなく、拡張されたディレクトリのルートからのみファイルを取得することを意味します。これは、jdkのclassloader.getResources()メソッドの制限から生じています。このResourcePatterNresolverの実装は、URLClassLoaderの紹介と「java.class.path」マニフェスト評価を介したJARルートルックアップ制限を軽減しようとしています。ただし、携帯性の保証なし。
つまり、ClassPath*を使用して他のJARパッケージを一致させる場合、前にディレクトリのレイヤーが必要である必要があります。そうしないと、一致しません。これは、classloader.getResources()関数によって引き起こされます。
IDEで実行する場合、アプリケーションが依存する他のモジュールは通常クラスディレクトリであるため、通常は問題ありません。
ただし、Fat Jarで走ると、他のモジュールが瓶としてパッケージ化され、Boot-INF/LIBの下に配置されているため、現時点では野生分布が失敗します。
要約します
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。