Spring のコンテナー API には、Bean メタデータ、そのメタデータからオブジェクトを 作成するファクトリ、ファクトリとアプリケーションサービスを調整するアプリケーション コンテキストという 3 つの層があります。これらの層を分離すると、Spring のソース コードと拡張ポイントを理解しやすくなります。
Bean 定義とレジストリ #
BeanDefinition は 1 つの Bean の可変メタデータです。Bean クラスまたはクラス名、
スコープ、コンストラクター引数、プロパティ値、修飾子、ファクトリメソッド、
ライフサイクルメソッド、役割、ソース位置、明示的な依存関係を記録します。
親子メタデータ関係は Java 継承から独立しています。
一般的な実装は異なる登録経路に対応します。
RootBeanDefinitionは Bean ファクトリが使用するマージ済み定義を表します。ChildBeanDefinitionは名前付き親定義からメタデータを継承します。GenericBeanDefinitionはマージ前に、スタンドアロンまたは親由来のメタデータを表現できます。AnnotatedGenericBeanDefinitionは登録されたクラスのアノテーションメタデータを公開します。ScannedGenericBeanDefinitionはコンポーネントクラスを先にロードせず、クラスパス スキャン時に読み取ったメタデータを公開します。
BeanDefinitionRegistry は Bean 名で定義を保存します。中心的な操作は定義の登録、
削除、問い合わせです。DefaultListableBeanFactory と GenericApplicationContext が
重要な実装です。
AnnotatedBeanDefinitionReader は明示的に指定されたコンポーネントクラスを登録します。
var context = new GenericApplicationContext();
var reader = new AnnotatedBeanDefinitionReader(context);
reader.register(OrderService.class);
context.refresh();ClassPathBeanDefinitionScanner はパッケージから候補コンポーネントを検索し、その
定義を登録します。どちらの仕組みもアノテーションスコープ、命名、修飾子、条件、
BeanDefinitionCustomizer コールバックを適用します。カスタマイザーはレジストリ
ポストプロセッサーを実装せず、登録時に対象を絞ったメタデータ変更を行えます。
BeanFactory、FactoryBean、ObjectFactory
#
BeanFactory は実行時レジストリと依存関係解決 API です。定義を検索し、Bean を作成し、
協働オブジェクトを解決し、シングルトンの同一性を管理し、ライフサイクルプロセッサーを
適用します。ListableBeanFactory は列挙を追加し、HierarchicalBeanFactory は親検索
を追加し、ConfigurableListableBeanFactory はフレームワーク基盤へコンテナー設定を
公開します。アプリケーションコードはサービスロケーターとして getBean() を呼ぶ
のではなく、ドメインの協働オブジェクトに依存します。
似た名前の 3 つの型には異なる責務があります。
BeanFactoryはコンテナーです。FactoryBean<T>は別のオブジェクトを作成する Bean です。名前を検索すると生成物が 返り、名前に&を付けるとファクトリ自体が返ります。getObjectType()とisSingleton()は生成物を説明します。ObjectFactory<T>はgetObject()を持つ最小のコールバックです。Spring は遅延取得 と内部作成コールバックに使用します。ObjectProvider<T>は任意、順序付き、ストリーム ベースのアクセスを加えます。
アプリケーションコンテキスト階層 #
ApplicationContext は ListableBeanFactory、
HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher,
ResourcePatternResolver, and related environment capabilities.
ConfigurableApplicationContext は refresh()、close()、環境設定、設定可能な
ファクトリへのアクセスなどのライフサイクル操作を追加します。
AbstractApplicationContext は refresh アルゴリズムを実装します。特殊化された基底
クラスが定義をファクトリへ届ける方法を決定します。
GenericApplicationContextは内部に 1 つのDefaultListableBeanFactoryを所有します。 1 回のrefresh()呼び出し前に、そのレジストリ API で定義を登録できます。AnnotationConfigApplicationContextは汎用コンテキストにAnnotatedBeanDefinitionReaderとClassPathBeanDefinitionScannerを組み合わせます。コンストラクターでクラスを 登録するかパッケージをスキャンし、その後 refresh できます。- Servlet 対応コンテキストは Web スコープと Servlet リソースを追加しますが、同じ コアファクトリ契約を維持します。
一部の古いコンテキスト実装は refresh 中に Bean ファクトリを再作成しますが、
GenericApplicationContext は refresh の繰り返しをサポートしません。フレームワークの
拡張は、すべてのコンテキストが複数回 refresh 可能だと仮定せず、具体的なコンテキスト
のライフサイクルに従います。
refresh と生成される定義 #
アノテーション登録は、指定されたクラスの定義を最初に作成します。refresh 中に
ConfigurationClassPostProcessor が @Configuration、コンポーネントスキャン、import、
@Bean メソッドを解析し、通常の Bean がインスタンス化される前に追加定義を登録します。
レジストリポストプロセッサーも同じ段階で定義を生成できます。Spring の AOT 処理は
事前に登録コードを生成できますが、結果の定義は同じ Bean ファクトリモデルへ渡されます。
ApplicationStartup はライフサイクルの意味を変えずに起動を計測します。
DefaultApplicationStartup は低オーバーヘッドの no-op 実装、BufferingApplicationStartup
は上限付きステップデータを保持し、FlightRecorderApplicationStartup は Java Flight
Recorder イベントを出力します。StartupStep には名前、タグ、明示的な終了があります。
起動計測はクリティカルパスで実行されるため、カスタム基盤はタグを低コストに保ちます。
拡張ポイントを選択する #
要件に合う最も狭い層を使用します。
BeanDefinitionCustomizerで登録時に定義をカスタマイズする。BeanDefinitionRegistryPostProcessorまたはBeanFactoryPostProcessorでメタデータを追加・変換する。BeanPostProcessorでインスタンスをインターセプトする。FactoryBeanでオブジェクトを生成する Bean を構築する。GenericApplicationContextまたはアプリケーションコンテキストのサブタイプで完全な 調整コンテナーを構築する。
コメント
GitHub で閲覧・コメントする(投稿にはログインが必要です)