1. 概要

Spring Frameworkには、BeanFactoryApplicationContextの2つのIOCコンテナーが付属しています。 BeanFactory はIOCコンテナーの最も基本的なバージョンであり、ApplicationContextBeanFactoryの機能を拡張します。

このクイックチュートリアルでは、実際の例を使用して、これら2つのIOCコンテナーの重要な違いを理解します。

2. 遅延読み込みと 熱心な読み込み

BeanFactoryはオンデマンドでBeanをロードしますが、ApplicationContextは起動時にすべてのBeanをロードします。 したがって、 BeanFactory は、ApplicationContextと比較して軽量です。 例を挙げて理解しましょう。

2.1. BeanFactoryによる遅延読み込み

シングルトンbeanクラスがStudentと呼ばれ、次の1つのメソッドがあるとします。

public class Student {
    public static boolean isBeanInstantiated = false;

    public void postConstruct() {
        setBeanInstantiated(true);
    }

    //standard setters and getters
}

postConstruct()メソッドは、BeanFactory構成ファイルioc-container-difference-example.xmlでinit-methodとして定義します。

<bean id="student" class="com.baeldung.ioccontainer.bean.Student" init-method="postConstruct"/>

次に、 Bean Factory を作成して、 Studentbeanがロードされるかどうかを確認するテストケースを作成しましょう。

@Test
public void whenBFInitialized_thenStudentNotInitialized() {
    Resource res = new ClassPathResource("ioc-container-difference-example.xml");
    BeanFactory factory = new XmlBeanFactory(res);
    
    assertFalse(Student.isBeanInstantiated());
}

ここで、Studentオブジェクトは初期化されていません。 つまり、BeanFactoryのみが初期化されます BeanFactory で定義されたBeanは、 getBean()メソッドを明示的に呼び出した場合にのみロードされます。

Student beanの初期化を確認してみましょう。ここでは、 get Bean()メソッドを手動で呼び出しています。

@Test
public void whenBFInitialized_thenStudentInitialized() {
    Resource res = new ClassPathResource("ioc-container-difference-example.xml");
    BeanFactory factory = new XmlBeanFactory(res);
    Student student = (Student) factory.getBean("student");

    assertTrue(Student.isBeanInstantiated());
}

ここで、StudentBeanが正常にロードされます。 したがって、 BeanFactory は、必要な場合にのみBeanをロードします。

2.2. ApplicationContextを使用した熱心な読み込み

それでは、BeanFactory。の代わりにApplicationContextを使用しましょう。

ApplicationContext、のみを定義し、積極的な読み込み戦略を使用してすべてのBeanを即座に読み込みます。

@Test
public void whenAppContInitialized_thenStudentInitialized() {
    ApplicationContext context = new ClassPathXmlApplicationContext("ioc-container-difference-example.xml");
    
    assertTrue(Student.isBeanInstantiated());
}

ここでは、 getBean()メソッドを呼び出さなくても、Studentオブジェクトが作成されます。

ApplicationContext は、その熱心な読み込み戦略が起動時にすべてのBeanを読み込むため、重いIOCコンテナーと見なされます。 BeanFactory は、比較すると軽量であり、メモリに制約のあるシステムで便利です。 それでも、次のセクションで、ほとんどのユースケースでApplicationContextが推奨される理由を説明します

3. エンタープライズアプリケーションの機能

ApplicationContext は、 BeanFactory をよりフレームワーク指向のスタイルで拡張し、エンタープライズアプリケーションに適したいくつかの機能を提供します。

たとえば、メッセージング(i18nまたは国際化)機能、イベント公開機能、注釈ベースの依存性注入、およびSpringAOPとの簡単な統合を提供します機能

これとは別に、 ApplicationContext はほぼすべてのタイプのBeanスコープをサポートしますが、BeanFactorySingletonPrototypeの2つのスコープのみをサポートします。 したがって、複雑なエンタープライズアプリケーションを構築する場合は、ApplicationContextを使用することをお勧めします。

4. BeanFactoryPostProcessorおよびBeanPostProcessorの自動登録

ApplicationContextは、起動時にBeanFactoryPostProcessorとBeanPostProcessorを自動的に登録します。 一方、BeanFactoryはこれらのインターフェースを自動的に登録しません。

4.1. BeanFactoryへの登録

理解するために、2つのクラスを書いてみましょう。

まず、 CustomBeanFactoryPostProcessor クラスがあります。これは、BeanFactoryPostProcessorを実装します。

public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    private static boolean isBeanFactoryPostProcessorRegistered = false;
    
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory){
        setBeanFactoryPostProcessorRegistered(true);
    }

    // standard setters and getters
}

ここでは、 postProcessBeanFactory()メソッドをオーバーライドして、その登録を確認しました。

次に、BeanPostProcessorを実装する別のクラスCustomBeanPostProcessorがあります。

public class CustomBeanPostProcessor implements BeanPostProcessor {
    private static boolean isBeanPostProcessorRegistered = false;
    
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName){
        setBeanPostProcessorRegistered(true);
        return bean;
    }

    //standard setters and getters
}

ここでは、 postProcessBeforeInitialization()メソッドをオーバーライドして、その登録を確認しました。

また、ioc-container-difference-example.xml構成ファイルで両方のクラスを構成しました。

<bean id="customBeanPostProcessor" 
  class="com.baeldung.ioccontainer.bean.CustomBeanPostProcessor" />
<bean id="customBeanFactoryPostProcessor" 
  class="com.baeldung.ioccontainer.bean.CustomBeanFactoryPostProcessor" />

起動時にこれら2つのクラスが自動的に登録されるかどうかを確認するテストケースを見てみましょう。

@Test
public void whenBFInitialized_thenBFPProcessorAndBPProcessorNotRegAutomatically() {
    Resource res = new ClassPathResource("ioc-container-difference-example.xml");
    ConfigurableListableBeanFactory factory = new XmlBeanFactory(res);

    assertFalse(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());
    assertFalse(CustomBeanPostProcessor.isBeanPostProcessorRegistered());
}

テストからわかるように、自動登録は行われませんでした

次に、BeanFactoryに手動で追加するテストケースを見てみましょう。

@Test
public void whenBFPostProcessorAndBPProcessorRegisteredManually_thenReturnTrue() {
    Resource res = new ClassPathResource("ioc-container-difference-example.xml");
    ConfigurableListableBeanFactory factory = new XmlBeanFactory(res);

    CustomBeanFactoryPostProcessor beanFactoryPostProcessor 
      = new CustomBeanFactoryPostProcessor();
    beanFactoryPostProcessor.postProcessBeanFactory(factory);
    assertTrue(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());

    CustomBeanPostProcessor beanPostProcessor = new CustomBeanPostProcessor();
    factory.addBeanPostProcessor(beanPostProcessor);
    Student student = (Student) factory.getBean("student");
    assertTrue(CustomBeanPostProcessor.isBeanPostProcessorRegistered());
}

ここでは、 postProcessBeanFactory()メソッドを使用して CustomBeanFactoryPostProcessor を登録し、 addBeanPostProcessor()メソッドを使用してCustomBeanPostProcessorを登録しました。 この場合、両方とも正常に登録されます。

4.2. ApplicationContextへの登録

前述したように、 ApplicationContext は、追加のコードを記述せずに両方のクラスを自動的に登録します。

単体テストでこの動作を確認しましょう。

@Test
public void whenAppContInitialized_thenBFPostProcessorAndBPostProcessorRegisteredAutomatically() {
    ApplicationContext context 
      = new ClassPathXmlApplicationContext("ioc-container-difference-example.xml");

    assertTrue(CustomBeanFactoryPostProcessor.isBeanFactoryPostProcessorRegistered());
    assertTrue(CustomBeanPostProcessor.isBeanPostProcessorRegistered());
}

ご覧のとおり、この場合、両方のクラスの自動登録が成功します

したがって、 Spring 2.0(およびそれ以降)は BeanPostProcessorを頻繁に使用するため、ApplicationContextを使用することを常にお勧めします。

また、プレーンなBeanFactoryを使用している場合、トランザクションやAOPなどの機能は有効になりません(少なくとも追加のコード行を記述しない限り)。 構成に問題がないため、混乱を招く可能性があります。

5. 結論

この記事では、ApplicationContextBeanFactoryの主な違いを実際の例で見てきました。

ApplicationContext には、エンタープライズアプリケーション向けのいくつかの機能を含む高度な機能が付属していますが、BeanFactoryには基本機能のみが付属しています。 したがって、通常は ApplicationContext、、およびを使用することをお勧めします。BeanFactoryは、メモリ消費が重要な場合にのみ使用する必要があります

いつものように、記事のコードはGitHubから入手できます。