Основные реализации: Spring предоставляет разные классы, реализующие ApplicationContext, для разных целей – например:
ClassPathXmlApplicationContext, FileSystemXmlApplicationContext – загружают бины из XML-файла (classpath или файловая система),
AnnotationConfigApplicationContext – принимает на вход Java-конфигурацию (классы @Configuration или пакет для сканирования аннотаций),
WebApplicationContext (например, AnnotationConfigWebApplicationContext) – специальный контекст для веб-приложений, интегрируется с сервлет-контейнером.
В современном коде напрямую создаются обычно только контексты на основе Java-конфига (AnnotationConfigApplicationContext) или XML, а веб-контейнер инициирует WebApplicationContext автоматически при старте приложения.
Использование в Spring Boot: Приложения на Spring Boot сами поднимают контейнер через вызов SpringApplication.run(...). Этот вызов возвращает готовый ApplicationContext, который уже загружен с вашими бинами. Разработчику редко нужно явно создавать или закрывать контекст вручную – Boot сделает это, а доступ к бинам происходит либо через авто-внедрение (@Autowired), либо через вызов ApplicationContext.getBean(...) при необходимости.
Пояснение:
ApplicationContext можно назвать «сердцем» Spring-приложения. Это объект, который хранит в себе все определения бинов и управляет их состоянием. Когда мы говорим, что "Spring создает бины и связывает их", именно ApplicationContext этим занимается. Он реализует интерфейс BeanFactory (наследует его), то есть умеет получать бин по имени или типу (getBean(String name) или getBean(MyClass.class)). Но на этом его роль не заканчивается.
В отличие от базового BeanFactory, ApplicationContext автоматически загружает все бины при инициализации (в случае eager синглтонов) и выполняет необходимый сервисный функционал вокруг них. Одна из таких возможностей – обработка BeanPostProcessor и BeanFactoryPostProcessor. Эти скрытые герои Spring позволяют расширять поведение бинов после их создания. Например, поддержка аннотации @Autowired реализована BeanPostProcessor'ом (он проходит по свежесозданному объекту и ищет поля/методы для внедрения), а поддержка аннотации @PostConstruct или интерфейса InitializingBean – тоже через специальный пост-процессор. Если использовать только BeanFactory, то подобных автоматических вещей не случится – их пришлось бы вызывать вручную. Поэтому в 99% случаев предпочитают ApplicationContext как основной контейнер.
Более того, ApplicationContext сразу готов к применению в enterprise-среде: он может собирать конфигурацию из нескольких источников (несколько XML-файлов или классов), тогда как BeanFactory оперирует одним источником определения бинов. Контекст поддерживает механизм событий: он публикует события, когда контекст запущен, когда закрыт, а также дает пользователю определять свои события и слушателей. Например, можно подписаться на событие ContextRefreshedEvent (контекст обновлен) или создать свое событие UserCreatedEvent и опубликовать его – все соответствующие бины-слушатели получат уведомление. BeanFactory подобных вещей не умеет. Также ApplicationContext включает поддержку MessageSource – это способ интернационализации. Вы можете в любом месте через context.getMessage("code", null, locale) получить локализованную строку из подключенных .properties-файлов. Все эти дополнительные возможности делает ApplicationContext полноценной инфраструктурной платформой для приложения.
На практике, чтобы воспользоваться ApplicationContext, нужно его инициализировать. В простом Java-приложении (без Spring Boot) это делается так, например:
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
// либо с Java-конфигурацией:
ApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
После этого context загрузит все бины, выполнит их связывание. Вы можете запросить бин:
Service service = context.getBean(Service.class);
service.doSomething();
и Spring вернет вам готовый объект Service с уже внедренными в него зависимостями. Если бин реализует интерфейс ApplicationContextAware или другие специальные интерфейсы, контекст вызовет соответствующие методы (например, передаст ссылку на себя через setApplicationContext для Aware-бинов). Также, если какие-то бины зарегистрированы как CommandLineRunner или ApplicationRunner (в Spring Boot), контекст их выполнит после запуска. В конце работы приложения можно закрыть контекст методом ((ConfigurableApplicationContext) context).close(), чтобы вызвать методы @PreDestroy/DisposableBean у бинов и освободить ресурсы.
В веб-приложениях на Spring контекст обычно поднимается автоматически. В традиционных сервлет-приложениях используется слушатель, объявленный в web.xml (например, ContextLoaderListener), который создает WebApplicationContext при старте сервера. В Spring Boot (при аннотации @SpringBootApplication) под капотом будет создан либо AnnotationConfigServletWebServerApplicationContext (для веб-приложения), либо обычный AnnotationConfigApplicationContext (для консольного приложения). Boot сам сконфигурирует бины веб-слоя, свяжет контроллеры, запустит встроенный сервер – все через тот же механизм контекста.
Отдельно стоит упомянуть, что ApplicationContext может иметь иерархию: один контекст родительский, другой дочерний. Это используется, например, в Spring MVC, где существует корневой контекст приложения (с сервисами, репозиториями) и отдельный контекст сервлетов DispatcherServlet (с только веб-специфичными бинами, типа контроллеров, привязанных к конкретному DispatcherServlet). Дочерний контекст видит бины родителя, а родитель – нет. Иерархия контекстов позволяет изолировать части приложения, если нужно.
В заключение, ApplicationContext – предпочтительный выбор контейнера при работе со Spring. Как сказано в официальной документации, “You should use an ApplicationContext unless you have a specific need for BeanFactory”. BeanFactory сам по себе сейчас используется только внутри Spring (например, DefaultListableBeanFactory лежит под капотом ApplicationContext) или в особых случаях для экономии памяти. Все ключевые функции Spring (аннотации, АОП, и т.д.) рассчитаны на работу через ApplicationContext, поэтому разработчик напрямую с BeanFactory практически не взаимодействует docs.spring.io.
Итак, контейнер ApplicationContext – это тот самый объект, который управляет всем жизненным циклом ваших объектов в Spring. Понимание его работы позволяет эффективнее настраивать контекст приложения (например, разбивать на профили, использовать события) и правильно инициализировать Spring-приложения. В большинстве случаев вам не нужно создавать его вручную – фреймворк сделает это за вас – однако методы взаимодействия с ним (получение бинов, публикация событий) могут пригодиться.
Конец части материала (Spring Framework: основные понятия IoC, DI, конфигурация и ApplicationContext).
