Spring コンテナにおける二つのファクトリー概念
Spring フレームワークを学習する際、命名規則が似ているBeanFactoryとFactoryBeanの違いは、初心者が混乱しやすいポイントの一つです。両者はいずれも Spring のインバージョンオブジェクト(IoC)コンテナの中核的な役割を果たしていますが、その目的と動作には明確な差異があります。特に技術面接では、この二つの関係を正確に理解しているかが問われる頻度が高いトピックです。
BeanFactory:IoC コンテナの最底层インターフェース
BeanFactoryは、Spring が提供する最も基本的な DI コンテナ定義です。このインタフェースは、すべての Bean のインスタンス化、初期化、破棄といったライフサイクル管理の仕様を規定しています。つまり、Spring はこのファクトリーを通じて Bean間の依存関係を解決し、属性注入を行うのです。
開発現場でより高レベルな機能を持つApplicationContextを利用することが一般的ですが、その内部構造をトレースすると、実際の Bean 取得処理は結局このBeanFactory委譲されていることがわかります。ApplicationContextは環境設定やメッセージリソース管理等のリッチな機能を追加しますが、Bean の生成ロジック自体は内部的なBeanFactory実装に任されています。
コンテナの起動プロセスを簡略化して表現すると、以下の流れとなります。
- コンテキスト環境の構築(ApplicationContextの準備)
- Bean 定義情報(BeanDefinition)の読み込み
- Bean ファクトリーへの定義登録
- ファクトリーによる Bean のインスタンス生成とキャッシュ管理
特にシングルトンスコープを持つ Bean については、初回生成時に内部的な Map キャッシュ(SingletonRegistry)へ登録されます。これにより、後続の取得要求において同一インスタンスが保証され、パフォーマンス最適化も図られています。
FactoryBean:特殊な生成機能を備えた Bean
対照的にFactoryBeanは、Bean そのものとしての振る舞いをしつつ、別の Bean を生成する「生産者」の役割を担います。名前末尾にBeanがつくことから、これは特定の Bean 類型を示すための特別な拡張インタフェースであると言えます。
主な特徴は以下の通りです。
- Spring コンテナによって管理される正規の Bean リストに含まれる。
- getObject()メソッドを実装することで、他のオブジェクトを作成・返却する。
インタフェース内の主要メソッドは次のようになっています。
// 作成されるオブジェクトを返す
T getObject() throws Exception;
// 対象とするクラス情報を返す
Class<?> getObjectType();
// 生成されるオブジェクトがシングルトンかどうかを判定
boolean isSingleton();
具体的な実装例
以下では、通常のビジネスロジックとは切り離した形で、FactoryBeanの実装イメージを記述します。
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;
@Component("dbConnectionProvider")
public class ConnectionProvider implements FactoryBean<DataSource> {
@Override
public DataSource getObject() throws Exception {
// ここで実際の DataSource オブジェクトを生成または取得する
return new SimpleDataSource("jdbc:mysql://localhost/test");
}
@Override
public Class<?> getObjectType() {
return DataSource.class;
}
@Override
public boolean isSingleton() {
return true; // 通常はtrue
}
}
ここで注目すべきは、コンテナに登録される Bean の名前はConnectionProviderですが、そこからgetBean("dbConnectionProvider")を取得すると、DataSource型が返される点です。
内部機構とキャッシャー挙動
実際の実行フローを確認すると、Spring が内部的に保持するキャッシュ構造に違いが存在します。
- BeanFactory の単一实例キャッシュ:ConnectionFactoryそのもののインスタンスではなく、getObject()の結果(DataSourceなど)が保存される。
- FactoryBean Object Cache:FactoryBean自身の実体を格納するための別途領域が存在する場合がある。
デフォルト動作として、ユーザーはファクトリー自身のインスタンスよりも、それが製造した結果物を受け取ることを意図しています。もしファクトリー自体を取得したい場合は、名前頭に&プレフィックスを付与する必要があります(例:getBean("&dbConnectionProvider"))。
概念整理と要約
両者の関係を整理すると、以下の比喩で説明するのがわかりやすいでしょう。
- BeanFactory:自動車工場全体。多数の部品から完成車までの全工程を管理する巨大なシステム。
- FactoryBean:工場内に設置された特定のロボットアーム。特定の部品だけを生産するために配置された、特殊な自動化装置。
このように、BeanFactoryは広範な管理権限を持つ基盤インターフェースであり、FactoryBeanはその中で特定製品を作成するための補助的なツールという位置付けになります。