Рубрики
Без рубрики

Разница между BeanFactory и ApplicationContext

Узнайте о существенных различиях между ApplicationContext Spring и BeanFactory на практических примерах

Автор оригинала: baeldung.

1. Обзор

Фреймворк Spring поставляется с двумя контейнерами IOC – BeanFactory и ApplicationContext . BeanFactory является самой базовой версией контейнеров IOC, а ApplicationContext расширяет возможности BeanFactory .

В этом кратком руководстве мы поймем существенные различия между этими двумя контейнерами IOC с практическими примерами.

2. Ленивая загрузка против Нетерпеливая Загрузка

BeanFactory загружает бобы по требованию, в то время как ApplicationContext загружает все бобы при запуске . Таким образом, BeanFactory является легким по сравнению с ApplicationContext . Давайте разберемся в этом на примере.

2.1. Ленивая Загрузка С BeanFactory

Предположим, у нас есть одноэлементный боб класс с именем Student с одним методом:

public class Student {
    public static boolean isBeanInstantiated = false;

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

    //standard setters and getters
}

Мы определим метод PostConstruct() как init-метод в нашем файле конфигурации BeanFactory , ioc-container-difference-example.xml :

Теперь давайте напишем тестовый случай, который создает BeanFactory , чтобы проверить, загружает ли он Student been:

@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 , будут загружены только тогда, когда мы явно вызовем метод getBean () /.

Давайте проверим инициализацию нашего Student bean, где мы вручную вызываем метод getBean() :

@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());
}

Здесь компонент Student успешно загружается. Следовательно, BeanFactory загружает боб только тогда, когда это необходимо.

2.2. Нетерпеливая Загрузка С Помощью ApplicationContext

Теперь давайте использовать ApplicationContext вместо BeanFactory.

Мы определим только ApplicationContext, и он мгновенно загрузит все компоненты, используя стратегию нетерпеливой загрузки:

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

Здесь, в Студент объект создается, даже если мы не вызывали getBean() метод.

ApplicationContext считается тяжелым контейнером IOC, поскольку его стратегия нетерпеливой загрузки загружает все компоненты при запуске. BeanFactory является легким по сравнению и может быть удобен в системах с ограниченным объемом памяти. Тем не менее, мы увидим в следующих разделах, почему ApplicationContext предпочтительнее для большинства случаев использования .

3. Функции корпоративного приложения

ApplicationContext расширяет BeanFactory в более ориентированном на фреймворк стиле и предоставляет несколько функций, подходящих для корпоративных приложений.

Например, он обеспечивает обмен сообщениями (i18n или интернационализацию) функциональность, публикацию событий функциональность, внедрение зависимостей на основе аннотаций и легкую интеграцию с функциями Spring AOP .

Кроме того, ApplicationContext поддерживает почти все типы областей bean, но BeanFactory поддерживает только две области — Singleton и Prototype . Поэтому всегда предпочтительнее использовать ApplicationContext при создании сложных корпоративных приложений.

4. Автоматическая регистрация BeanFactoryPostProcessor и BeanPostProcessor

ApplicationContext автоматически регистрирует BeanFactoryPostProcessor и BeanPostProcessor при запуске. С другой стороны, BeanFactory не регистрирует эти интерфейсы автоматически.

4.1. Регистрация в BeanFactory

Чтобы понять, давайте напишем два класса.

Во-первых, у нас есть Пользовательский класс BeanFactoryPostProcessor , который реализует BeanFactoryPostProcessor :

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

    // standard setters and getters
}

Здесь мы переопределили метод postProcessBeanFactory () , чтобы проверить его регистрацию.

Во-вторых, у нас есть другой класс, Custom BeanPostProcessor , который реализует BeanPostProcessor :

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 файл конфигурации:


Давайте рассмотрим тестовый случай, чтобы проверить, регистрируются ли эти два класса автоматически во время запуска:

@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());
}

Как мы видим из нашего теста, автоматической регистрации не произошло .

Теперь давайте рассмотрим тестовый случай, который вручную добавляет их в Бобовый завод :

@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() для регистрации пользовательского BeanFactoryPostProcessor и метод addBeanPostProcessor() для регистрации пользовательского BeanPostProcessor . Оба они успешно регистрируются в этом случае.

4.2. Регистрация в ApplicationContext

Как мы уже отмечали ранее, ApplicationContext регистрирует оба класса автоматически без написания дополнительного кода.

Давайте проверим это поведение в модульном тесте:

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

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

Как мы видим, автоматическая регистрация обоих классов в этом случае успешна .

Поэтому всегда рекомендуется использовать ApplicationContext , поскольку Spring 2.0 (и выше) в значительной степени использует BeanPostProcessor.

Также стоит отметить, что если вы используете обычный BeanFactory, то такие функции, как транзакции и AOP, не вступят в силу (по крайней мере, без написания дополнительных строк кода). Это может привести к путанице, потому что в конфигурации ничего не будет выглядеть неправильно.

5. Заключение

В этой статье мы рассмотрели ключевые различия между ApplicationContext и BeanFactory на практических примерах.

ApplicationContext поставляется с расширенными функциями, в том числе несколькими, ориентированными на корпоративные приложения, в то время как BeanFactory поставляется только с базовыми функциями. Поэтому обычно рекомендуется использовать ApplicationContext, и мы должны использовать BeanFactory только тогда, когда потребление памяти критично .

Как всегда, код для статьи доступен на GitHub .