Родственные души в Spring IOC: BeanFactory и ApplicationContext

Spring исходный код
Родственные души в Spring IOC: BeanFactory и ApplicationContext

BeanFactory & FactoryBean

Говоря о родственных душах в Spring, разве это не BeanFactory и FactoryBean? Эти двое не только похожи друг на друга, они неразлучны в вопросах интервью, в парах. Однако на самом деле отношения между ними подобны прохожему в жизни, лишь беглый взгляд, а затем забывание друг друга в реках и озерах.
Однако FactoryBean не одинок. ObjcetFactory вдалеке находится далеко. В этой статье не ставится цель подробно разобрать эти два интерфейса, но читатели могут понять их как инкубаторы указанного типа Bean. Мы можем изменить Bean через эти два интерфейса поведение при инициализации. Но между ними все же есть большая разница.

BeanFactory & ApplicationContext

В повседневной работе мы часто называем BeanFactory контейнером, а ApplicationContext — контекстом. Не знаю, задумывались ли вы когда-нибудь об отношениях между ними.Семейство интерфейсов Spring AwareВ этой статье я подробно объяснил, как получить BeanFactory и ApplicationContext в текущей рабочей среде, и мы могли бы найти ответ в коде.

  • класс конфигурации
package com.spring.container;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.spring.container")
public class ContainerConfig {

}
  • Получить обе информации
package com.spring.container;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * @Author: Raphael
 */
@Component
public class SpringIoc implements BeanFactoryAware, ApplicationContextAware {

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.err.println(System.identityHashCode(beanFactory));
        System.out.println(beanFactory.getClass().getName());
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        System.err.println(System.identityHashCode(applicationContext));
        System.out.println(applicationContext.getClass().getName());
    }

}
  • стартовый класс
package com.spring.container;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author: Raphael
 */
public class MainContainer {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(ContainerConfig.class);
        context.close();
    }

}
  • результат

Очевидно, что это не только не один и тот же объект, но и разные типы. Видя, что познание большинства людей здесь нарушено, потому что подсознательно они думают, что на самом деле это одно и то же. На самом деле у них даже не было наследственных отношений, что прямо разрушило фантазию другой волны. Если вы мне не верите, давайте взглянем на диаграммы классов UML для этих двух классов.

Сколько контейнеров?

Проницательные люди действительно обнаружили противоречие, и разумно, что корневой контейнер Spring должен иметь один и только один. Но это явно два объекта, которые не имеют ничего общего друг с другом.Весенняя официальная документацияОтношения между ними описываются следующим образом:

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

Согласно официальному объяснению: это отношения между содержанием и содержанием, поэтому можем ли мы получить корневой контейнер в ApplicationContext?
Бог сказал: должен быть свет, поэтому пришла функция getAutowireCapableBeanFactory().

package com.spring.container;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * @Author: Raphael
 */
@Component
public class SpringIoc implements BeanFactoryAware, ApplicationContextAware {

    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
        System.err.println(System.identityHashCode(beanFactory));
        System.out.println(beanFactory.getClass().getName());
    }

    // 直接打印两个对象的比对结果
    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        AutowireCapableBeanFactory factory =
                applicationContext.getAutowireCapableBeanFactory();
        System.err.println(factory.hashCode());
        System.out.println(factory.getClass().getName());
        System.out.println("二者相等吗:    " + (factory == beanFactory));
    }

}

Результаты проверки полностью подтверждают официальное описание.

DefaultListableBeanFactory

Официальное определение его таково:

Реализация Spring по умолчанию {@link ConfigurableListableBeanFactory}, {@link BeanDefinitionRegistry}

Зрелая бобовая фабрика
Метаданные на основе определений bean-компонентов, расширяемые постпроцессорами

Яркий перед сценой — это BeanFactory, но тот, кто несет нагрузку, — это DefaultListableBeanFactory Очевидно, что это фильм с участием трех человек, но я не могу назвать его. Итак, когда создается объект DefaultListableBeanFactory? Новый вопрос снова не давал мне покоя. Ответ на самом деле неотделим от инициализации IOC-контейнера, поэтому я не буду здесь вдаваться в подробности. Мы лишь кратко проанализируем мыслительный процесс DefaultListableBeanFactory для генерации объектов.
мы вMainContainerВызывается следующий конструктор:

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    this();
    register(annotatedClasses);
    refresh();
}

Поскольку AnnotationConfigApplicationContext наследует GenericApplicationContext, одновременно будет вызываться конструктор родительского класса, и в это время рождается объект-контейнер.

public GenericApplicationContext() {
    this.beanFactory = new DefaultListableBeanFactory();
}

Затем функция refresh() вызывает методgetFreshBeanFactory().

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    refreshBeanFactory();
    return getBeanFactory();
}

getBeanFactory() — это абстрактный метод, определенный в AbstractApplicationContext. Также реализовано GenericApplicationContext.

public final ConfigurableListableBeanFactory getBeanFactory() {
    return this.beanFactory;
}

Здесь фактически возвращается объект, созданный его собственным методом построения, в AnnotationConfigApplicationContext. Когда мы проследили этот уровень, нам наконец-то открылась тайна жизненного опыта объекта-контейнера. На самом деле причина, по которой ApplicationContext имеет возможность Beanfactory, заключается в том, что работа с контейнером делегируется его собственному внутреннему объекту-контейнеру. Например:

public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
    assertBeanFactoryActive();
    return getBeanFactory().getBean(name, requiredType);
}

На самом деле он не имеет здесь подробной реализации этого метода, а получает собственный внутренний объект-контейнер через getBeanFactory(), а затем передает его ta для реализации. Теперь контекст должен быть достаточно ясен. Исходный код Spring представляет собой набор шаблонов проектирования, который фактически используется здесь.Комбинированный режим.

Разница между двумя

На самом деле, официальное резюме обоих из них

Пакеты org.springframework.beans и org.springframework.context являются основой контейнера IoC Spring Framework. Интерфейс BeanFactory предоставляет расширенный механизм настройки, способный управлять любым типом объекта. ApplicationContext является его субинтерфейсом.

Были добавлены следующие функции:

  • Простая интеграция с возможностями АОП Spring.
  • Обработка ресурсов сообщений (для интернационализации)
  • Релиз события
  • Специфический контекст прикладного уровня

Весенняя официальная документация, вы действительно не собираетесь пойти посмотреть его?

Наконец: Цветы хорошо растут, луна круглеет, и люди живут дольше.