Spring Beanのライフサイクルとプロトタイプスコープ

最終更新: 2025-11-17 23:19:46 +0800 +0800
原文は英語で書かれています。あなたはAI翻訳版を読んでいます。

SpringはBeanのメタデータとBeanインスタンスを分離します。BeanDefinitionは オブジェクトの作成方法を記述し、BeanFactoryはオブジェクトが要求されたときに その定義を適用します。ApplicationContextは、協調的な起動、 後処理、イベント、リソース読み込み、シャットダウンを追加します。

コンテキストのリフレッシュ中に行われる処理 #

AbstractApplicationContext.refresh()は、アプリケーションのシングルトンを 利用可能にする前に、環境とBeanファクトリを準備します。主なステージは次のとおりです。

  1. BeanFactoryを準備または取得し、Bean定義を読み込む。
  2. 定義をまだ変更できる段階で、設定クラスの処理を含む BeanFactoryPostProcessorsを呼び出す。
  3. BeanPostProcessorsを検出して登録する。
  4. メッセージ解決、イベント、コンテキスト固有のリソースなどの コンテキスト基盤を初期化する。
  5. 残りの非遅延初期化シングルトンBeanをインスタンス化する。
  6. リフレッシュ済みの状態とContextRefreshedEventを公開する。

BeanFactoryPostProcessorはメタデータを変更します。一方、 BeanPostProcessorはインスタンスを認識し、フィールドを注入したり、 ライフサイクルアノテーションを呼び出したり、Beanをプロキシに置き換えたりできます。 すべてのポストプロセッサが登録される前にインスタンス化される可能性があるため、 ファクトリポストプロセッサから通常のアプリケーションBeanを作成するのは安全ではありません。

依存関係の順序とdepends-on #

コンテナは、依存するBeanより前に、そのBeanのコンストラクタ依存関係と プロパティ依存関係を作成します。したがって、コンストラクタインジェクションは 必須の関係と作成順序の両方を表します。

java
@Component
final class ReportService {
    private final ReportRepository repository;

    ReportService(ReportRepository repository) {
        this.repository = repository;
    }
}

@DependsOn("schemaInitializer")またはXMLのdepends-onは、共有外部リソースの 初期化など、インジェクション関係が存在しない場合に順序を追加します。 シングルトンBeanの場合、破棄順序も逆転します。つまり、依存するBeanは、 それが依存するBeanより先に破棄されます。depends-onはクラスが使用するものを 隠してしまうため、実際の型付き依存関係の代わりに使用すべきではありません。

インスタンスの初期化 #

通常のBeanに対して、Springは次の処理を行います。

  1. 通常はコンストラクタまたはファクトリメソッドを呼び出して、オブジェクトをインスタンス化する。
  2. プロパティとフィールドを解決して注入する。
  3. BeanNameAware、BeanFactoryAware、ApplicationContextAwareなどの awareコールバックを呼び出す。
  4. 初期化前に各BeanPostProcessorを呼び出す。
  5. @PostConstruct、続いてInitializingBean.afterPropertiesSet()、 さらに設定されたカスタムinitメソッドを呼び出す。
  6. 初期化後に各BeanPostProcessorを呼び出す。

Springの基盤は、ポストプロセッサを通じてこのシーケンスの一部を実装します。 そのため、カスタムプロセッサは順序に関する契約を遵守する必要があります。 初期化後のプロセッサは、元のオブジェクトではなくプロキシを返す場合があります。 呼び出し元が準備済みの、場合によってはアドバイスされたオブジェクトを受け取るのは、 チェーン全体が完了した後だけです。

必須の不変条件を確立する場所としては、コンストラクタインジェクションが最も安全です。 @PostConstructは、初期化が注入されたプロパティや、コンストラクタでは利用できない コンテナサービスに依存する場合に適しています。

破棄とコンテキストのシャットダウン #

設定可能なコンテキストを閉じると、管理対象のシングルトンが破棄されます。 各Beanについて、Springは@PreDestroy、DisposableBean.destroy()、 設定されたカスタムdestroyメソッドを呼び出します。ただし、アダプタの重複メソッド チェックが適用されます。SmartLifecycleは、協調的なシャットダウンを必要とする コンポーネント向けに、フェーズ付きの停止コールバックを追加します。

アプリケーションは、手動で作成したコンテキストを閉じるか、 registerShutdownHook()でシャットダウンフックを登録する必要があります。 Spring Bootは、通常のプロセスシャットダウンの一環としてアプリケーションコンテキストを閉じます。 プロセスの突然の終了ではコールバックが保証されないため、永続的な正しさを コールバックだけに依存してはなりません。

プロトタイプの所有権 #

プロトタイプスコープでは、コンテナへのリクエストごとに新しいインスタンスが生成されます。 プロトタイプをシングルトンに直接注入すると、解決はシングルトンの作成時に一度だけ行われ、 そのフィールドには同じプロトタイプインスタンスが保持されます。各操作で新しいインスタンスが 必要な場合は、ObjectProvider<T>、JakartaのProvider<T>、メソッドインジェクション、 またはスコーププロキシを使用します。

Springはプロトタイプを完全に初期化して呼び出し元に返しますが、インスタンスを保持せず、 後で破棄コールバックを呼び出すこともありません。したがって、所有権は受け取り側に移ります。 ファイル、ソケット、またはエグゼキュータを保持するプロトタイプを取得するコードは、 それを明示的に閉じる必要があります。集中管理されたクリーンアップが必要な場合は、 カスタムBeanPostProcessorでそのようなインスタンスを追跡できますが、 明示的なリソース所有権の方が明確です。

主要なリファレンス #

コメント

GitHub で閲覧・コメントする(投稿にはログインが必要です)