spring что такое application context
Подготовка к Spring Professional Certification. Контейнер, IoC, бины
Доброго времени суток, Хабр.
Сегодня я решил представить вам перевод цикла статей для подготовки к Spring Professional Certification.
Это перевод только первой статьи, если он зайдет аудитории, я продолжу выпуск переводов.
Внедрение зависимостей — это специальный паттерн, который уменьшает связь между Spring компонентами. Таким образом, при применении DI, ваш код становится чище, проще, его становится легче понять и тестировать.
Согласно паттерну DI, создание объектов для зависимостей переходит на фабрику или отдается третьей стороне. Это означает, что мы можем сосредоточиться на использовании этих объектов вместо их создания.
В Spring Framework интерфейс org.springframework.factory.BeanFactory предоставляет фабрику для бинов, которая в то же время является IoC контейнером приложения. Управление бинами основано на конфигурации(java или xml).
Интерфейс org.springframework.context.ApplicationContext — это обертка над bean factory, предоставляющая некоторые дополнительные возможности, например AOP, транзакции, безопасность, i18n, и т.п.
Основа Spring Framework — контейнер, и наши объекты «живут» в этом контейнере.
Контейнер обычно создает множество объектов на основе их конфигураций и управляет их жизненным циклом от создания объекта до уничтожения.
Контейнер — это объект, реализующий интерфейс ApplicationContext.
Spring обеспечивает несколько разновидностей контекста.
Есть несколько основных реализаций интерфейса ApplicationContext:
Примеры создания контекста:
Если вы используете JUnit 5, то вам нужно указать 2 аннотации:
Если это не веб-приложение, то есть 2 способа:
В Spring Boot приложении:
Этот класс поместит в контейнер экземпляр класса DataSource. Позднее его можно будет использовать при доступе к базе данных.
Component scanning(сканирование компонентов) — Spring автоматически обнаруживает бины, которые будут находиться в контейнере. Это бины с аннотациями-стереотипами.
Component | Корневая аннотация, которая помечает класс как кандидат для автовнедрения |
Controller | Указывает, что класс является контроллером для отправления данных на фронт. |
@RestController | Указывает, что класс является контроллером для REST. Содержит аннотации Controller и @ResponseBody |
Service | Указывает, что класс является сервисом для выполнения бизнес-логики |
Repository | Указывает, что класс является репозиторием для работы с бд |
@Configuration | Указывает, что класс содержит Java-конфигурацию(@Bean-методы) |
Область видимости — scope, скоуп. Существует 2 области видимости по умолчанию.
Singleton | Область видимости по умолчанию. В контейнере находится всего 1 экземпляр бина |
Prototype | В контейнере может находится любое количество экземпляров бина |
И 4 области видимости в веб-приложении.
Request | Область видимости — 1 HTTP запрос. На каждый запрос создается новый бин |
Session | Область видимости — 1 сессия. На каждую сессию создается новый бин |
Application | Область видимости — жизненный цикл ServletContext |
WebSocket | Область видимости — жизненный цикл WebSocket |
Область видимости указывается с помощью аннотации @Scope на @Bean методах.
Prototype Scope не потокбезопасный, т.к. он не гарантирует что один и тот же экземпляр будет вызываться только в 1 потоке.
Singleton Scope же наоборот потокобезопасный.
Singleton-бины обычно создаются сразу при сканировании.
Prototype-бины обычно создаются только после запроса.
Singleton bean можно внедрять в любой другой бин.
Prototype может быть зависимостью для любого бина.
Внедрять можно только singleton или prototype.
Для того чтобы использовать кастомный BFPP. Вы можете переопределить механизм получения данных из метафайлов.
Есть 3 варианта для создания таких методов:
Ниже перечислены типы DI, которые могут быть использованы в вашем приложении:
DI через конструктор считается самым лучшим способом, т.к. для него не надо использовать рефлексию, а также он не имеет недостатков DI через сеттер.
DI через поле не рекомендуется использовать, т.к. для этого применяется рефлексия, снижающая производительность.
DI через конструктор может приводить к циклическим зависимостям. Чтобы этого избежать, можно использовать ленивую инициализацию бинов или DI через сеттер.
Контейнер обрабатывает DI с помощью AutowiredAnnotationBeanPostProcessor. В связи с этим, аннотация не может быть использована ни в одном BeanFactoryPP или BeanPP.
Если внедряемый объект массив, коллекция, или map с дженериком, то Spring внедрит все бины подходящие по типу в этот массив(или другую структуру данных). В случае с map ключом будет имя бина.
Вы можете использовать разные типы внедрения:
Spring предоставляет аннотацию Qualifier, чтобы преодолеть проблему неоднозначности при DI.
Если в контейнере есть несколько бинов одного типа(SomeClass), то контейнер внедрит именно тот бин, над @Bean-методом которого стоит соответствующий квалификатор. Также можно не ставить квалификатор на метод, а использовать имя бина в качестве параметра квалификатора.
Имя бина можно можно указать через параметр аннотации Bean, а по умолчанию это имя фабричного метода.
Прокси это специальный объект, который имеет такие же публичные методы как и бин, но у которого есть дополнительная функциональность.
Два вида прокси:
Если в контейнере нет экземпляра бина, то вызывается @Bean-метод. Если экземпляр бина есть, то возвращается уже созданный бин.
В эту переменную будет внедрена строка, например из property или из view.
Как обычно, просьба присылать правки или найденные ошибки в личку.
Spring: в поисках контекста
Пару месяцев назад в моем профиле был опубликован подробный пост по загрузке классов на JVM. После этого доклада мои коллеги задались хорошим вопросом: а какой механизм использует Spring для разбора конфигураций и как он загружает классы из контекста?
После многих часов дебага спринговых исходников мой коллега экспериментальным путём докопался до той самой простой и понятной правды.
Немного теории
Сразу определим, что ApplicationContext — это главный интерфейс в Spring-приложении, который предоставляет информацию о конфигурации приложения.
Перед тем, как перейти непосредственно к демонстрации, взглянем на этапы формирования ApplicationContext:
В этом посте разберем первый этап, так как нас интересует именно чтение конфигураций и создание BeanDefinition.
BeanDefinition — это интерфейс, который описывает бин, его свойства, аргументы конструктора и другую метаинформацию.
Что касается конфигурации самих бинов, у Spring есть 4 способа конфигурации:
Xml конфигурация
За основу берем простой проект:
Здесь следует немного пояснить, какие методы и для чего используются:
В 25 строке идет объявление и инициализация ApplicationContext через конфигурацию Xml.
Конфигурационный Xml-файл выглядит следующим образом:
При конфигурации бина указываем реально существующий class. Обратите внимание на заданное свойство lazy-init=”true”: в этом случае бин будет создаваться только после запроса его из контекста.
Смотрим, как Spring при поднятии контекста разрулит ситуацию с классами, объявленными в конфигурационном файле:
Разберемся с деталями Xml конфигурации:
— Чтением файла конфигурации занимается класс XmlBeanDefinitionReader, который реализует интерфейс BeanDefinitionReader;
— XmlBeanDefinitionReader на входе получает InputStream и загружает Document через DefaultDocumentLoader:
— После этого каждый элемент этого документа обрабатывается и, если он является бином, создается BeanDefinition на основе заполненных данных (id, name, class, alias, init- method, destroy-method и др.):
— Каждый BeanDefinition помещается в Map, который хранится в классе DefaultListableBeanFactory:
В коде Map выглядит следующим образом:
Теперь в том же конфигурационном файле добавим еще одно объявление бина с классом film.BadVillain:
Смотрим, что получится, если распечатать список созданных BeanDefenitionNames и загруженные классы:
Несмотря на то, что класса film.BadVillain, указанного в конфигурационном файле, не существует, Spring отрабатывает без ошибок:
Cписок BeanDefenitionNames содержит 2 элемента; то есть, те 2
BeanDefinition, сконфигурированные в нашем файле, были созданы.
Конфигурации обоих бинов, по сути, одинаковы. Но, при этом существующий класс загрузился, никаких проблем не возникло. Из чего можно сделать вывод, что попытка загрузить несуществующий класс также была, но провальная попытка ничего не сломала.
Попытаемся получить еще и сами бины по их именам:
Если в первом случае был получен валидный бин, то во втором случае прилетел exception.
Обратите внимание на stack trace: сработала отложенная загрузка классов. Выполняется обход всех загрузчиков классов в попытке найти искомый класс среди загруженных ранее. И после того, как нужный класс не был найден, с помощью вызова метода Utils.forName, происходит попытка найти несуществующий класс по имени, что привело к получению закономерной ошибки.
При поднятии контекста загрузился только один класс, при этом попытка загрузки несуществующего файла не привела к ошибке. Почему так произошло?
Всё потому, что мы прописали lazy-init:true и запретили Spring создавать экземпляр бина, где и генерируется полученный ранее exception. Если убрать это свойство из конфигурации либо изменить его значение lazy-init:false, то описанная выше ошибка также вылетит, но не будет проигнорирована и приложение остановиться. В нашем случае контекст был проинициализирован, но мы не смогли создать экземпляр бина, т.к. указанный класс не был найден.
Groovy конфигурация
При конфигурации контекста с помощью Groovy-файла, необходимо сформировать GenericGroovyApplicationContext, который принимает на вход строку с конфигурацией контекста. Чтением контекста в данном случае занимается класс GroovyBeanDefinitionReader. Эта конфигурация работает по сути так же, как и Xml, только с Groovy-файлами. К тому же, GroovyApplicationContext нормально работает и с Xml-файлом.
Пример простого конфигурационного Groovy-файла:
Пробуем проделать то же самое, что и с Xml:
Ошибка вылетает сразу: Groovy так же, как и Xml, создает BeanDefenition’ы, но в данном случае постпроцессор сразу выдаёт ошибку.
Конфигурация через аннотации с указанием пакета для сканирования или JavaConfig
Данная конфигурация отличается от двух предыдущих. В конфигурация через аннотации используется 2 варианта: JavaConfig и аннотация над классами.
Здесь используется один и тот же контекст: AnnotationConfigApplicationContext(“package”/JavaConfig.class). Работает он в зависимости от того, что было передано в конструктор.
В контексте AnnotationConfigApplicationContext есть 2 приватных поля:
Создаем конфигурационный файл с максимально простым бином. Смотрим, что загрузится:
Если в случае с Xml и Groovy загрузилось столько BeanDefinition, сколько было объявлено, то в данном случае в процессе поднятия контекста загружаются как объявленные, так и дополнительные BeanDefinition. В случае реализации через JavaConfig все классы загружаются сразу, в том числе и класс самого JavaConfig, так как он сам является бином.
Еще один момент: в случае с Xml и Groovy конфигурациями загрузилось 343 файла, здесь же произошла более “тяжелая” загрузка количеством 631 доп файл.
Этапы работы ClassPathBeanDefinitionScanner:
Рассмотрим работу сканера на простом примере.
Создаем собственную аннотацию для поиска соответствующих классов:
Создаем 2 класса: один со стандартной аннотацией Component, второй — с кастомной аннотацией:
В результате получаем сформированные BeanDefinition для этих классов и успешно загруженные классы.
Вывод
Из всего вышесказанного на поставленные вопросы можно ответить следующим образом:
Spring изнутри. Этапы инициализации контекста
Доброго времени суток уважаемые хабравчане. Уже 3 года я работаю на проекте в котором мы используем Spring. Мне всегда было интересно разобраться с тем, как он устроен внутри. Я поискал статьи про внутреннее устройство Spring, но, к сожалению, ничего не нашел.
Всех, кого интересует внутреннее устройство Spring, прошу под кат.
На схеме изображены основные этапы поднятия ApplicationContext. В этом посте мы остановимся на каждом из этих этапов. Какой-то этап будет рассмотрен подробно, а какой-то будет описан в общих чертах.
1. Парсирование конфигурации и создание BeanDefinition
Цель первого этапа — это создание всех BeanDefinition. BeanDefinition — это специальный интерфейс, через который можно получить доступ к метаданным будущего бина. В зависимости от того, какая у вас конфигурация, будет использоваться тот или иной механизм парсирования конфигурации.
Xml конфигурация
Для Xml конфигурации используется класс — XmlBeanDefinitionReader, который реализует интерфейс BeanDefinitionReader. Тут все достаточно прозрачно. XmlBeanDefinitionReader получает InputStream и загружает Document через DefaultDocumentLoader. Далее обрабатывается каждый элемент документа и если он является бином, то создается BeanDefinition на основе заполненных данных (id, name, class, alias, init-method, destroy-method и др.). Каждый BeanDefinition помещается в Map. Map хранится в классе DefaultListableBeanFactory. В коде Map выглядит вот так.
Конфигурация через аннотации с указанием пакета для сканирования или JavaConfig
Конфигурация через аннотации с указанием пакета для сканирования или JavaConfig в корне отличается от конфигурации через xml. В обоих случаях используется класс AnnotationConfigApplicationContext.
Если заглянуть во внутрь AnnotationConfigApplicationContext, то можно увидеть два поля.
ClassPathBeanDefinitionScanner сканирует указанный пакет на наличие классов помеченных аннотацией @Component (или любой другой аннотацией которая включает в себя @Component). Найденные классы парсируются и для них создаются BeanDefinition.
Чтобы сканирование было запущено, в конфигурации должен быть указан пакет для сканирования.
Groovy конфигурация
Данная конфигурация очень похожа на конфигурацию через Xml, за исключением того, что в файле не XML, а Groovy. Чтением и парсированием groovy конфигурации занимается класс GroovyBeanDefinitionReader.
2. Настройка созданных BeanDefinition
После первого этапа у нас имеется Map, в котором хранятся BeanDefinition. Архитектура спринга построена таким образом, что у нас есть возможность повлиять на то, какими будут наши бины еще до их фактического создания, иначе говоря мы имеем доступ к метаданным класса. Для этого существует специальный интерфейс BeanFactoryPostProcessor, реализовав который, мы получаем доступ к созданным BeanDefinition и можем их изменять. В этом интерфейсе всего один метод.
Метод postProcessBeanFactory принимает параметром ConfigurableListableBeanFactory. Данная фабрика содержит много полезных методов, в том числе getBeanDefinitionNames, через который мы можем получить все BeanDefinitionNames, а уже потом по конкретному имени получить BeanDefinition для дальнейшей обработки метаданных.
Давайте разберем одну из родных реализаций интерфейса BeanFactoryPostProcessor. Обычно, настройки подключения к базе данных выносятся в отдельный property файл, потом при помощи PropertySourcesPlaceholderConfigurer они загружаются и делается inject этих значений в нужное поле. Так как inject делается по ключу, то до создания экземпляра бина нужно заменить этот ключ на само значение из property файла. Эта замена происходит в классе, который реализует интерфейс BeanFactoryPostProcessor. Название этого класса — PropertySourcesPlaceholderConfigurer. Весь этот процесс можно увидеть на рисунке ниже.
Давайте еще раз разберем что же у нас тут происходит. У нас имеется BeanDefinition для класса ClassName. Код класса приведен ниже.
Если PropertySourcesPlaceholderConfigurer не обработает этот BeanDefinition, то после создания экземпляра ClassName, в поле host проинжектится значение — «$
Соответственно в эти поля проинжектятся правильные значения.
Для того что бы PropertySourcesPlaceholderConfigurer был добавлен в цикл настройки созданных BeanDefinition, нужно сделать одно из следующих действий.
Для XML конфигурации.
PropertySourcesPlaceholderConfigurer обязательно должен быть объявлен как static. Без static у вас все будет работать до тех пор, пока вы не попробуете использовать @ Value внутри класса @Configuration.
3. Создание кастомных FactoryBean
На первый взгляд, тут все нормально и нет никаких проблем. А что делать если нужен другой цвет? Создать еще один бин? Не вопрос.
А что делать если я хочу каждый раз случайный цвет? Вот тут то и приходит на помощь интерфейс FactoryBean.
Создадим фабрику которая будет отвечать за создание всех бинов типа — Color.
Добавим ее в xml и удалим объявленные до этого бины типа — Color.
Теперь создание бина типа Color.class будет делегироваться ColorFactory, у которого при каждом создании нового бина будет вызываться метод getObject.
Для тех кто пользуется JavaConfig, этот интерфейс будет абсолютно бесполезен.
4. Создание экземпляров бинов
Созданием экземпляров бинов занимается BeanFactory при этом, если нужно, делегирует это кастомным FactoryBean. Экземпляры бинов создаются на основе ранее созданных BeanDefinition.
5. Настройка созданных бинов
Интерфейс BeanPostProcessor позволяет вклиниться в процесс настройки ваших бинов до того, как они попадут в контейнер. Интерфейс несет в себе несколько методов.
Процесс донастройки показан на рисунке ниже. Порядок в котором будут вызваны BeanPostProcessor не известен, но мы точно знаем что выполнены они будут последовательно.
Для того, что бы лучше понять для чего это нужно, давайте разберемся на каком-нибудь примере.
При разработке больших проектов, как правило, команда делится на несколько групп. Например первая группа разработчиков занимается написанием инфраструктуры проекта, а вторая группа, используя наработки первой группы, занимается написанием бизнес логики. Допустим второй группе понадобился функционал, который позволит в их бины инжектить некоторые значения, например случайные числа.
На первом этапе будет создана аннотация, которой будут помечаться поля класса, в которые нужно проинжектить значение.
По умолчанию, диапазон случайных числе будет от 0 до 10.
Затем, нужно создать обработчик этой аннотации, а именно реализацию BeanPostProcessor для обработки аннотации InjectRandomInt.
Код данного BeanPostProcessor достаточно прозрачен, поэтому мы не будем на нем останавливаться, но тут есть один важный момент.
BeanPostProcessor обязательно должен быть бином, поэтому мы его либо помечаем аннотацией @Component, либо регестрируем его в xml конфигурации как обычный бин.
Первая группа разработчиков свою задачу выполнила. Теперь вторая группа может использовать эти наработки.
В итоге, все бины типа MyBean, получаемые из контекста, будут создаваться с уже проинициализированными полями value1 и value2. Также тут стоить отметить, этап на котором будет происходить инжект значений в эти поля будет зависеть от того какой @ Scope у вашего бина. SCOPE_SINGLETON — инициализация произойдет один раз на этапе поднятия контекста. SCOPE_PROTOTYPE — инициализация будет выполняться каждый раз по запросу. Причем во втором случае ваш бин будет проходить через все BeanPostProcessor-ы что может значительно ударить по производительности.
Полный код программы вы можете найти тут.
Хочу сказать отдельное спасибо EvgenyBorisov. Благодаря его курсу, я решился на написание этого поста.
Также советую посмотреть его доклад с JPoint 2014.
Русские Блоги
Поговорим о BeanFactory и ApplicationContext во фреймворке Spring
Spring описывает отношения зависимости между Bean и Bean через файл конфигурации и использует функцию отражения Java для создания экземпляра Bean и установления отношения зависимости между Beans. Контейнер IoC Sprig также предоставляет расширенные услуги, такие как кэширование экземпляра компонента, управление жизненным циклом, прокси-сервер экземпляра компонента, публикация событий и загрузка ресурсов на основе выполнения этих основных задач.
Контекст приложения (com.springframework.context.ApplicationContext) основан на BeanFactory и предоставляет больше функций, ориентированных на приложения. Он обеспечивает поддержку интернационализации и систему событий каркаса, упрощая создание практических приложений.
1 BeanFactory
1.1 Архитектура классов
Существует множество реализаций BeanFactory. В версиях до Spring 3.2 наиболее часто используется XmlBeanFactory, который теперь является устаревшим. Рекомендуется использовать XmlBeanDefinitionReader и DefaultListableBeanFactory.
Интерфейс BeanFactory находится наверху дерева структуры класса. Его основным методом является getBean (String beanName), который возвращает объект Bean с определенным именем из контейнера. Функции BeanFactory постоянно расширяются с помощью других интерфейсов.
интерфейс | Описание |
---|---|
ListableBeanFactory | Этот интерфейс определяет несколько методов доступа к основной информации о компоненте в контейнере, например, просмотр количества компонентов, получение имени конфигурации определенного типа компонента или проверка того, содержит ли контейнер определенный компонент. |
HierarhicalBeanFactory | Интерфейс родительско-дочернего каскадного контейнера IoC, дочерний контейнер может получить доступ к родительскому контейнеру через метод интерфейса. |
ConfigurableBeanFactory | Этот интерфейс расширяет возможности настройки контейнера IoC. Он определяет такие методы, как загрузчик классов, редактор свойств, постпроцессор инициализации контейнера и т. Д. |
AutowireCapableBeanFactory | Определяет метод автоматической сборки компонента в контейнере в соответствии с определенными правилами (например, сопоставление по имени, сопоставление по типу). |
SingletonBeanFactory | Определяет методы, позволяющие регистрировать одноэкземплярные bean-компоненты в контейнере во время выполнения. |
BeanDefinitionRegistry | Каждый элемент узла Bean в файле конфигурации Spring представлен объектом BeanDefinition в контейнере Spring, который описывает информацию о конфигурации Bean. Интерфейс BeanDefinitionResgistry предоставляет метод для ручной регистрации объектов BeanDefinition в контейнере. |
1.2 Инициализация
Затем мы настраиваем Bean People в файле конфигурации Spring, затем загружаем файл конфигурации через BeanFactory и запускаем контейнер Ioc.
Файл конфигурации Spring:
Затем используйте DefaultListableBeanFactory и XmlBeanDefinitionReader для запуска контейнера Ioc:
XmlBeanDefinitionReader загружает информацию о конфигурации Spring через Resource и запускает контейнер Ioc, а затем вы можете получить Bean через BeanFactory # getBean (name). Инициализация компонента происходит при его первом вызове. Для одноэкземплярных bean-компонентов BeanFactory кэширует экземпляр Bean, поэтому второе использование метода getBean () будет напрямую получать экземпляр Bean из кеша контейнера IoC.
Примечание: При инициализации BeanFactory для него должна быть предоставлена структура журнала.Обычно используется Log4J, то есть файл конфигурации Log4J предоставляется в пути к классам, так что контейнер Spring можно запустить в обычном режиме.
2 ApplicationContext
ApplicationContext является производным от BeanFactory и предоставляет множество практических функций приложения. В BeanFactory многие функции должны быть реализованы программно, а в ApplicationContext они могут быть реализованы через конфигурацию.
2.1 Архитектура класса ApplicationContext
интерфейс | Описание |
---|---|
ApplicationEventPublisher | Позвольте контейнеру иметь функцию публикации событий контекста приложения, включая события запуска контейнера и события завершения работы. Компоненты, реализующие интерфейс мониторинга событий ApplicationListener, могут получать события контейнера и отвечать на события контейнера. В абстрактном классе реализации AbstractApplicationContext ApplicationContext есть ApplicationEventMulticaster, который отвечает за сохранение всех слушателей, чтобы они могли получать уведомления, когда контейнер генерирует события контекста. |
MessageSource | Предоставляет функцию международного доступа к информации i18n для контейнера. |
ResourcePatternResolver | Все классы реализации ApplicationContext имеют реализованные функции, аналогичные PathMatchingResourcePatternResolver, а файлы конфигурации Spring могут быть загружены с помощью префиксов пути к файлам классов ресурсов в стиле Ant. |
LifeCycle | Он предоставляет два метода, start () и stop (), которые в основном используются для управления асинхронной обработкой. При конкретном использовании этот интерфейс реализуется как ApplicationContext, так и конкретным Bean. ApplicationContext будет передавать информацию о запуске / остановке всем bean-компонентам в контейнере, которые реализуют этот интерфейс для достижения цели управления и контроля JMX и планирования задач. |
ConfigurableApplicationContext | Он расширяет ApplicationContext, давая ApplicationContext возможность запускать, обновлять и закрывать контекст приложения. Когда контекст закрыт, вызовите refresh (), чтобы запустить контекст; если он уже запущен, вызовите refresh (), чтобы очистить кеш и перезагрузить информацию о конфигурации; вызовите close (), чтобы закрыть контекст приложения. |
2.1.1 Конфигурация XML
При инициализации ApplicationContext выберите класс реализации ApplicationContext в соответствии с путем к файлу конфигурации.
Вы также можете указать набор файлов конфигурации, и Spring автоматически интегрирует содержимое нескольких файлов конфигурации:
Примечание. ClassPathXmlApplicationContext и FileSystemXmlApplicationContext также могут явно указывать путь с префиксом типа ресурса.
2.1.2 Конфигурация аннотации класса
Spring поддерживает настройку на основе аннотаций классов.Основная функция происходит из подпроекта Spring под названием JavaConfig. В настоящее время JavaConfig обновлен до части основной инфраструктуры Spring. POJO с аннотацией @Configuration может предоставить информацию о конфигурации Bean, требуемую Spring.
По сравнению с методом конфигурации XML, метод конфигурации, основанный на аннотации класса, позволяет разработчикам управлять процессом инициализации компонента, поэтому он более гибкий.
Конфигурация компонента на основе аннотаций класса должна использовать AnnotationConfigApplicationContext для запуска контейнера Spring:
2.1.3 Конфигурация Groovy DSL
Spring 4.x поддерживает использование Groovy DSL для настройки компонентов, с помощью которых может быть реализована сложная и гибкая логика конфигурации.
Сначала введите Groovy в pom.xml:
Затем добавьте файл конфигурации:
Наконец, используйте GenericGroovyApplicationContext для запуска контейнера:
2.2 Архитектура класса WebApplicationContext
WebApplicationContext предназначен для веб-приложений. Он позволяет загружать файл конфигурации из пути относительно корневого веб-каталога для завершения работы по инициализации. Ссылку на ServletContext можно получить из WebApplicationContext. Весь объект контекста веб-приложения будет помещен в качестве атрибута в ServletContext, чтобы веб-приложение могло Для доступа к контексту Spring Spring предоставляет метод getWebApplicationContext (ServletContext src) для WebApplicationContextUtils для получения экземпляра WebApplicationContext из ServletContext.
В среде приложений, отличных от веб-приложений, Bean имеет только две области: одноэлементную и прототипную. В WebApplicationContext он добавляет к Бину еще три области: запрос, сеанс и глобальный сеанс.
WebApplicationContext расширяет ApplicationContext. WebApplicationContext определяет константу ROOT_WEB_APPLICATION_ CONTEXT_ATTRIBUTE. Когда контекст запускается, экземпляр WebApplicationContext использует эту константу в качестве ключа и помещается в список атрибутов ServletContext. Таким образом, мы можем напрямую получить WebApplicationContext из веб-контейнера с помощью следующего оператора:
ConfigurableWebApplicationContext расширяет WebApplicationContext, что позволяет создавать экземпляр WebApplicationContext через конфигурацию, и определяет два важных метода:
Название метода | Описание |
---|---|
setServletContext(ServletContext servletContext) | Настройте контекст веб-приложения для Spring для интеграции двух |
setConfigLocations(String[] configLocations) | Задайте адрес файла конфигурации Spring. Как правило, адрес файла конфигурации зависит от адреса корневого веб-каталога, например /WEB-INF/config.xml. Однако пользователи также могут использовать адреса с префиксом типа ресурса, например classpath: net / deniro / beans.xml. |
2.3 Инициализировать контекст WebApplicationContext
WebApplicationContext требуется экземпляр ServletContext, у него должен быть веб-контейнер, чтобы завершить начальную работу. Мы можем настроить самозапускающийся сервлет или определить прослушиватель веб-контейнера (ServletContextListener) в web.xml. С помощью одного из этих двух элементов мы можем запустить контекст веб-приложения Spring.
нота: Все версии веб-контейнеров поддерживают самозапускающийся сервлет, но только веб-контейнеры Servlet 2.3 и выше поддерживают слушателей веб-контейнеров. Но некоторые веб-контейнеры являются исключением, например Weblogic 8.1, WebSphere 5.x, Oracle OC4J 9.0 и так далее.
Spring предоставляет прослушиватель сервлетов и веб-контейнеров для запуска WebApplicationContext:
* org.springframework.web.context.ContextLoaderServlet。
* org.springframework.web.context.ContextLoaderListener。
2.3.1 XML-метод
Давайте запустим WebApplicationContext с помощью ContextLoaderListener:
ContextLoaderListener получает местоположение файла конфигурации Spring через параметр контекста веб-контейнера contextConfigLocation. Вы можете указать несколько файлов конфигурации, и вы можете использовать запятые, пробелы или двоеточия для их разделения. Для путей к файлам без префикса типа ресурса WebApplicationContext будет по умолчанию использовать эти пути как корневой путь развертывания в Интернете. Конечно, вы также можете использовать конфигурацию пути с префиксом типа ресурса, например здесь classpath*:spring-*.xml 。
Если вы находитесь в веб-контейнере с низкой версией, который не поддерживает прослушиватели контейнеров, мы можем использовать ContextLoaderServlet для завершения работы по запуску, поскольку Spring 4 больше не поддерживает этот класс, поэтому мы не будем его повторять.
Поскольку WebApplicationContext должен использовать журнал, мы помещаем файл конфигурации Log4J в путь к классам WEB-INF / classes, чтобы механизм Log4J мог запускаться плавно. Если файл конфигурации Log4J находится в другом месте, вы должны указать расположение файла конфигурации Log4J в web.xml. Spring предоставляет два класса реализации, аналогичные запуску WebApplicationContext для включения механизма Log4J: Log4jConfigServlet (больше не поддерживается в Spring4) и Log4jConfigListener. Независимо от того, какой метод используется, необходимо убедиться, что информация о конфигурации Log4J может быть загружена до загрузки файла конфигурации Spring.
нота: Log4jConfigListener должен быть помещен перед ContextLoaderListener, чтобы гарантировать, что первый запускается первым, завершает загрузку файла конфигурации Log4J и инициализирует механизм Log4J, а затем запускает последний.
2.3.2 Метод аннотации
Вы также можете использовать аннотированный Java-класс @Configuration для предоставления информации о конфигурации:
В это время, если ContextLoaderListener находит параметр контекста contextClass, он будет использовать AnnotationConfigWebApplicationContext, указанный параметром, для инициализации контейнера. Класс реализации инициализирует контейнер в соответствии с информацией о конфигурации, предоставленной классом конфигурации @Configuration, указанным параметром contextConfigLocation.
2.3.3 Groovy DSL способ
Вы также можете использовать метод Groovy DSL, принцип аналогичен методу аннотации.
2.4 родительско-дочерний контейнер
Через интерфейс HierarchicalBeanFactory контейнер IoC Spring может установить иерархическую систему контейнеров «родитель-потомок». Дочерний контейнер может получить доступ к Bean в родительском контейнере, но родительский контейнер не может получить доступ к Bean дочернего контейнера. Внутри контейнера идентификатор bean-компонента должен быть уникальным, но дочерний контейнер может иметь bean-компонент с тем же идентификатором, что и родительский контейнер. Иерархия родительско-дочерних контейнеров повышает масштабируемость и гибкость контейнерной архитектуры Spring, поэтому третьи стороны могут программно добавлять один или несколько дочерних контейнеров специального назначения к существующему контейнеру для обеспечения некоторых дополнительных функций.
Spring использует характеристики родительско-дочерних контейнеров для достижения многих возможностей.Например, в Spring MVC Бин уровня представления расположен в дочернем контейнере, а Бины бизнес-уровня и уровня сохраняемости расположены в родительском контейнере. Таким образом, Бин уровня представления может относиться к бизнес-уровню и Бину уровня сохраняемости, но Бин бизнес-уровня и Бин уровня сохраняемости не может видеть Бин уровня представления.