この記事では、私が最近遭遇した問題について共有したいと思います。これは皆さんにとって興味深いと思います。
何が問題ですか?
テスト環境と本番環境のソース コードは同じであり、ローカル環境とテスト環境は両方とも正常に動作しますが、サービス クラスの NPE で実行される本番環境のみがロードに失敗し、新しい要件が追加されました。このクラスは、Customize パッケージ (自社開発ツールキット) からインターフェイスを継承します。
プロジェクトの構造
Customize の設計は、API とサービスを管理するために Spring に依存しています。 Springの自動スキャンでは、クラスの初期化時にApiEnhancerとServiceEnhancerの共通クラスが読み込まれ、ApplicationContextでインスタンスを取得します。デバッグの結果、ロード時に ApplicationContext が null であり、まだ初期化されていないことがわかりました。 ApplicationContextAwareの実装によりsetApplicationContextメソッド内で初期化されているため、setApplicationContextメソッドが実行されていないと推測されます。
ApplicationContextProvider クラスの読み込みプロセス中、初期化フェーズ中に静的メソッドがメソッド領域に読み込まれます。ただし、ApplicationContext を使用して Bean のインスタンスを取得する場合、静的メソッドはクラス名によって直接呼び出されます。 ApplicationContextProvider がヒープ内にメモリを割り当ててインスタンス化する前に API が作成されている限り、setApplicationContext メソッドは初期化のために呼び出されません。
applicationContextProvider はアノテーション @Component を使用し、Api はアノテーション @RestController を使用し、2 つのクラスは同じパスにあります。ただし、Spring がそれらをスキャンしてロードするとき、特定の順序はありません。つまり、両方のクラスがそれぞれ別のクラスの前に作成される可能性があります。運用環境では、API は applicationContextProvider の前に作成されるため、Bean を取得するためにクラス名によって静的メソッドが直接呼び出されるとき、applicationContext は初期化されていません。
解決策
ApplicationContextAware インターフェースの実装クラスの setApplicationContext メソッドが実行されていない場合は、まず実装クラスが遅延読み込みに設定されているか、プロジェクトでグローバル遅延読み込みが設定されているかを確認してください。
このプロジェクトでは、ApiEnhancer インターフェイスと ApplicationContextAware インターフェイスの実装クラスの作成順序が問題の原因でした。また、Api クラスはビジネス ロジックを処理する通常の RESTful API にすぎず、フロントから呼び出されたときにロードできます。最後のページ。したがって、遅延読み込みに変更することで問題は解決しました。
ロード順序の観点から、クラス間の依存関係を最小限に抑えることをお勧めします。やむを得ない場合は、遅延ロード、または @DependsOn、@Order、@Priority などのアノテーションを使用して、Bean のロード順序を制御できます。
本番環境とテスト環境の作成順序が異なるのはなぜですか?
Spring のスキャン処理を確認するためにデバッグしてみましょう。
ClassPathBeanDeterminationScanner の scan メソッドから始めます。
doScan メソッド
ClassPathScanningCandidateComponentProvider
の scanCandidateComponents メソッドPathMatchingResourcePatternResolver
の findAllClassPathResources メソッドdoFindPathMatchingJarResources メソッド
JarFile は、Java 標準ライブラリの java.util.jar パッケージ内のクラスで、ZipFile を継承および拡張します。 jarFile.entries() は、JarEntryIterator.
という名前のイテレータを返します。JarExitIterator は、JarFile の親クラスのエントリを反復する Iterator Pattern の実装です。
ZipFile のエントリ メソッドは、ZipExitIterator という名前のイテレータを返します。
ZipExitIterator の nextElement メソッドは next メソッドを呼び出し、次に getNextEntry メソッドを呼び出します。
getNextEntry は ネイティブ メソッドです。
ネイティブ メソッドは Java 以外の言語で実装され、Java 仮想マシン内で呼び出されて基礎となる機能を実装します。この機能は環境 (オペレーティング システムまたは JDK バージョン) によって異なる場合があります。 JAR パッケージ自体には順序がないため、実際の走査順序は、さまざまな JAR パッケージ化ツールや環境に応じて異なる場合があります。
以上がapplicationContextAware インターフェースの setApplicationContext メソッド実行の問題と Spring Bean の取得に失敗するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。