API-интерфейс BeanFactory обеспечивает базовую основу для IoC -функциональности в Spring. Его специфические контракты в основном используются в интеграции с другими частями Spring и соответствующими сторонними фреймворками, а его реализация DefaultListableBeanFactory является ключевым делегатом в высокоуровневом контейнере GenericApplicationContext.

BeanFactory и связанные с ним интерфейсы (такие как BeanFactoryAware, InitializingBean, DisposableBean) являются важными точками интеграции для других компонентов фреймворка. Не требуя никаких аннотаций или даже рефлексии, они обеспечивают очень эффективное взаимодействие между контейнером и его компонентами. Бины уровня приложения могут использовать те же интерфейсы обратного вызова, но обычно отдается предпочтение декларативному внедрение зависимостей либо через аннотации, либо через программную конфигурацию.

Обратите внимание, что основной уровень API BeanFactory и его реализация DefaultListableBeanFactory не предусматривают предположений о формате конфигурации или аннотациях компонентов, которые будут использоваться. Все эти разновидности входят в состав расширений (таких как XmlBeanDefinitionReader и AutowiredAnnotationBeanPostProcessor) и работают с общими объектами BeanDefinition в качестве основного представления метаданных. Именно это делает контейнер Spring столь гибким и расширяемым.

BeanFactory или ApplicationContext?

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

ApplicationContext стоит использовать - если у вас нет веских причин не делать этого - с GenericApplicationContext и его подклассом AnnotationConfigApplicationContext в качестве общих реализаций для специальной реализации начальной загрузки. Это основные точки входа в основной контейнер Spring для всех общих целей: загрузки конфигурационных файлов, запуска сканирования пути классов, программной регистрации определений бинов и аннотированных классов, а также (начиная с версии 5.0) регистрации функциональных определений бинов.

Поскольку ApplicationContext предоставляет все функциональные возможности BeanFactory, его обычно рекомендуется использовать вместо обычного BeanFactory, за исключением сценариев, где необходим полный контроль над обработкой бинов. Внутри ApplicationContext (например, в реализации GenericApplicationContext) несколько видов бинов определяются по соглашению (то есть по имени или типу бинов - в частности, это касается постпроцессоров), в то время как обычный DefaultListableBeanFactory не зависит ни от каких специализированных бинов.

Для многих расширенных возможностей контейнера, таких как обработка аннотаций и АОП-проксирование, точка расширения BeanPostProcessor имеет основополагающее значение. Если вы используете только обычный DefaultListableBeanFactory, то такие постпроцессоры не будут обнаружены и активированы по умолчанию. Данная ситуация может сбить с толку, поскольку на самом деле с вашей конфигурацией бинов все в порядке. Скорее, в таком сценарии начальную загрузку контейнера нужно выполнить с помощью дополнительных настроек.

В следующей таблице перечислены возможности, предоставляемые интерфейсами и реализациями BeanFactory и ApplicationContext.

Таблица 9. Матрица признаков
Признак BeanFactory ApplicationContext
Создание экземпляров/связывание бинов Да Да
Интегрированное управление жизненным циклом Нет Да
Автоматическая регистрация BeanPostProcessor Нет Да
Автоматическая регистрация BeanFactoryPostProcessor Нет Да
Удобный доступ к MessageSource (для интернационализации) Нет Да
Встроенный механизм публикации ApplicationEvent Нет Да

Чтобы явно зарегистрировать постпроцессор бинов с помощью DefaultListableBeanFactory, необходимо программно вызвать addBeanPostProcessor, как показано в следующем примере:

Java
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// заполняем фабрику определениями бина
// теперь регистрируем все необходимые экземпляры BeanPostProcessor
factory.addBeanPostProcessor(new AutowiredAnnotationBeanPostProcessor());
factory.addBeanPostProcessor(new MyBeanPostProcessor());
// теперь начнем использовать фабрику
Kotlin
val factory = DefaultListableBeanFactory()
// заполняем фабрику определениями бина
// теперь регистрируем все необходимые экземпляры BeanPostProcessor
factory.addBeanPostProcessor(AutowiredAnnotationBeanPostProcessor())
factory.addBeanPostProcessor(MyBeanPostProcessor())
// теперь начнем использовать фабрику

Чтобы применить BeanFactoryPostProcessor к обычному DefaultListableBeanFactory, необходимо вызвать его метод postProcessBeanFactory, как показано в следующем примере:

Java
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(new FileSystemResource("beans.xml"));
// вводим некоторые значения свойств из файла свойств Properties
PropertySourcesPlaceholderConfigurer cfg = new PropertySourcesPlaceholderConfigurer();
cfg.setLocation(new FileSystemResource("jdbc.properties"));
// теперь на самом деле выполняем замену
cfg.postProcessBeanFactory(factory);
Kotlin
val factory = DefaultListableBeanFactory()
val reader = XmlBeanDefinitionReader(factory)
reader.loadBeanDefinitions(FileSystemResource("beans.xml"))
// вводим некоторые значения свойств из файла свойств Properties
val cfg = PropertySourcesPlaceholderConfigurer()
cfg.setLocation(FileSystemResource("jdbc.properties"))
// теперь на самом деле выполняем замену
cfg.postProcessBeanFactory(factory)

В обоих случаях явные шаги регистрации неудобны, поэтому различные варианты ApplicationContext предпочтительнее простого DefaultListableBeanFactory в приложениях на базе Spring, особенно если полагаться на экземпляры BeanFactoryPostProcessor и BeanPostProcessor для обеспечения расширенной функциональности контейнера в типичной корпоративной среде.

В AnnotationConfigApplicationContext зарегистрированы все общие постпроцессоры аннотаций, а также можно добавить дополнительные процессоры через конфигурационные аннотации, такие как @EnableTransactionManagement. На уровне абстракции конфигурационной модели Spring, основанной на аннотациях, понятие постпроцессоров бинов становится просто детализацией внутреннего контейнера.