Spring context что это

Spring Framework – первые шаги (Конспект пятый)

В предыдущей лекции мы определились, что Application context – это описание среды окружения, т.е. в файловой системе он может присутствовать как набор конфигурационных файлов.

Конспект пятый : Application context (продолжение)

В то же время, в библиотеке классов Spring Framework существует интерфейс org.springframework.context.ApplicationContext, предоставляющий следующие возможности:

Существует несколько способов „поднятия“ application context. Для иллюстрации я остановлюсь на простейшем способе, который с успехом можно использовать при разработке юнит тестов. Давайте рассмотрим его пример:

Как видно из примера, первой строкой метода main, мы загружаем контекст приложения из файла registratoApplicationContext.xml (см. предыдущую лекцию). После чего, с помощью метода getBean() у нас появляется возможность получить доступ ко всем компонентам, объявленным в соответствующем контексте.

Однако следует отметить тот факт, что единого мнения о пользе „вынесенного конфигурирования в отдельный xml файл“ нет. С одной стороны, у нас складывается впечатление, что конфигурирование, вынесенное за рамки кода, позволяет выполнять его (конфигурирование) не программистом системы, а скажем администратором!? C другой стороны, Мартин Фаулер в своих статьях ставит под сомнение тот факт, что подобное конфигурирование может выполнить человек не посвященный в таинства всей системы, ну и кроме того получается, что каждая платформа обрастает своими конфигурационными файлами: у Spring свой формат xml-файлов, у Struts – свой, jBoss, TomCat… etc. Т.о. разрабочик все время должен держать себя в тонусе и отслеживать все изменения, происходящие в Java-сообществе, для того чтобы не выпасть из обоймы ;).

Очевидно, что все вышесказанное заставляет задуматься архитекторов о том, чтобы привести декларативное конфигурирование системы к единому стандарту, понятному всем Java разработчикам. Альтернативным подходом в данном случае является использование анотаций, появившихся в J2SE 5.0. И работы в этом направлении ведутся. Это подтверждает и появление EJB 3.0, и наметившийся трэнд в Spring Framework – с каждой новой версией разработчики Spring поддерживают все большее количество анотаций, позволяющих сконфигурировать систему непосредственно в коде приложения. Сейчас мы не будем останавливаться на этих возможностях Их мы рассмотрим в одной из следующих лекций.

Источник

Spring: в поисках контекста

Пару месяцев назад в моем профиле был опубликован подробный пост по загрузке классов на JVM. После этого доклада мои коллеги задались хорошим вопросом: а какой механизм использует Spring для разбора конфигураций и как он загружает классы из контекста?

Spring context что это. vz z001zifi89ni. Spring context что это фото. Spring context что это-vz z001zifi89ni. картинка Spring context что это. картинка vz z001zifi89ni

После многих часов дебага спринговых исходников мой коллега экспериментальным путём докопался до той самой простой и понятной правды.

Немного теории

Сразу определим, что ApplicationContext — это главный интерфейс в Spring-приложении, который предоставляет информацию о конфигурации приложения.

Перед тем, как перейти непосредственно к демонстрации, взглянем на этапы формирования ApplicationContext:

Spring context что это. voco dc. Spring context что это фото. Spring context что это-voco dc. картинка Spring context что это. картинка voco dc

В этом посте разберем первый этап, так как нас интересует именно чтение конфигураций и создание 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, сконфигурированные в нашем файле, были созданы.

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

Попытаемся получить еще и сами бины по их именам:

Spring context что это. image loader. Spring context что это фото. Spring context что это-image loader. картинка Spring context что это. картинка image loader

Если в первом случае был получен валидный бин, то во втором случае прилетел exception.

Обратите внимание на stack trace: сработала отложенная загрузка классов. Выполняется обход всех загрузчиков классов в попытке найти искомый класс среди загруженных ранее. И после того, как нужный класс не был найден, с помощью вызова метода Utils.forName, происходит попытка найти несуществующий класс по имени, что привело к получению закономерной ошибки.

При поднятии контекста загрузился только один класс, при этом попытка загрузки несуществующего файла не привела к ошибке. Почему так произошло?

Всё потому, что мы прописали lazy-init:true и запретили Spring создавать экземпляр бина, где и генерируется полученный ранее exception. Если убрать это свойство из конфигурации либо изменить его значение lazy-init:false, то описанная выше ошибка также вылетит, но не будет проигнорирована и приложение остановиться. В нашем случае контекст был проинициализирован, но мы не смогли создать экземпляр бина, т.к. указанный класс не был найден.

Groovy конфигурация

При конфигурации контекста с помощью Groovy-файла, необходимо сформировать GenericGroovyApplicationContext, который принимает на вход строку с конфигурацией контекста. Чтением контекста в данном случае занимается класс GroovyBeanDefinitionReader. Эта конфигурация работает по сути так же, как и Xml, только с Groovy-файлами. К тому же, GroovyApplicationContext нормально работает и с Xml-файлом.

Пример простого конфигурационного Groovy-файла:

Пробуем проделать то же самое, что и с Xml:

Spring context что это. image loader. Spring context что это фото. Spring context что это-image loader. картинка Spring context что это. картинка image loader

Ошибка вылетает сразу: Groovy так же, как и Xml, создает BeanDefenition’ы, но в данном случае постпроцессор сразу выдаёт ошибку.

Конфигурация через аннотации с указанием пакета для сканирования или JavaConfig

Данная конфигурация отличается от двух предыдущих. В конфигурация через аннотации используется 2 варианта: JavaConfig и аннотация над классами.

Здесь используется один и тот же контекст: AnnotationConfigApplicationContext(“package”/JavaConfig.class). Работает он в зависимости от того, что было передано в конструктор.

В контексте AnnotationConfigApplicationContext есть 2 приватных поля:

Создаем конфигурационный файл с максимально простым бином. Смотрим, что загрузится:

Spring context что это. image loader. Spring context что это фото. Spring context что это-image loader. картинка Spring context что это. картинка image loader

Если в случае с Xml и Groovy загрузилось столько BeanDefinition, сколько было объявлено, то в данном случае в процессе поднятия контекста загружаются как объявленные, так и дополнительные BeanDefinition. В случае реализации через JavaConfig все классы загружаются сразу, в том числе и класс самого JavaConfig, так как он сам является бином.

Еще один момент: в случае с Xml и Groovy конфигурациями загрузилось 343 файла, здесь же произошла более “тяжелая” загрузка количеством 631 доп файл.

Этапы работы ClassPathBeanDefinitionScanner:

Рассмотрим работу сканера на простом примере.

Создаем собственную аннотацию для поиска соответствующих классов:

Создаем 2 класса: один со стандартной аннотацией Component, второй — с кастомной аннотацией:

В результате получаем сформированные BeanDefinition для этих классов и успешно загруженные классы.

Spring context что это. image loader. Spring context что это фото. Spring context что это-image loader. картинка Spring context что это. картинка image loader

Вывод

Из всего вышесказанного на поставленные вопросы можно ответить следующим образом:

Источник

Spring изнутри. Этапы инициализации контекста

Spring context что это. image loader. Spring context что это фото. Spring context что это-image loader. картинка Spring context что это. картинка image loader

Доброго времени суток уважаемые хабравчане. Уже 3 года я работаю на проекте в котором мы используем Spring. Мне всегда было интересно разобраться с тем, как он устроен внутри. Я поискал статьи про внутреннее устройство Spring, но, к сожалению, ничего не нашел.

Всех, кого интересует внутреннее устройство Spring, прошу под кат.

На схеме изображены основные этапы поднятия ApplicationContext. В этом посте мы остановимся на каждом из этих этапов. Какой-то этап будет рассмотрен подробно, а какой-то будет описан в общих чертах.

Spring context что это. image loader. Spring context что это фото. Spring context что это-image loader. картинка Spring context что это. картинка image loader

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. Весь этот процесс можно увидеть на рисунке ниже.

Spring context что это. image loader. Spring context что это фото. Spring context что это-image loader. картинка Spring context что это. картинка image loader

Давайте еще раз разберем что же у нас тут происходит. У нас имеется BeanDefinition для класса ClassName. Код класса приведен ниже.

Если PropertySourcesPlaceholderConfigurer не обработает этот BeanDefinition, то после создания экземпляра ClassName, в поле host проинжектится значение — «$» (в остальные поля проинжектятся соответсвующие значения). Если PropertySourcesPlaceholderConfigurer все таки обработает этот BeanDefinition, то после обработки, метаданные этого класса будут выглядеть следующим образом.

Соответственно в эти поля проинжектятся правильные значения.

Для того что бы PropertySourcesPlaceholderConfigurer был добавлен в цикл настройки созданных BeanDefinition, нужно сделать одно из следующих действий.

Для XML конфигурации.

PropertySourcesPlaceholderConfigurer обязательно должен быть объявлен как static. Без static у вас все будет работать до тех пор, пока вы не попробуете использовать @ Value внутри класса @Configuration.

3. Создание кастомных FactoryBean

На первый взгляд, тут все нормально и нет никаких проблем. А что делать если нужен другой цвет? Создать еще один бин? Не вопрос.

А что делать если я хочу каждый раз случайный цвет? Вот тут то и приходит на помощь интерфейс FactoryBean.

Создадим фабрику которая будет отвечать за создание всех бинов типа — Color.

Добавим ее в xml и удалим объявленные до этого бины типа — Color.

Теперь создание бина типа Color.class будет делегироваться ColorFactory, у которого при каждом создании нового бина будет вызываться метод getObject.

Для тех кто пользуется JavaConfig, этот интерфейс будет абсолютно бесполезен.

4. Создание экземпляров бинов

Созданием экземпляров бинов занимается BeanFactory при этом, если нужно, делегирует это кастомным FactoryBean. Экземпляры бинов создаются на основе ранее созданных BeanDefinition.

Spring context что это. image loader. Spring context что это фото. Spring context что это-image loader. картинка Spring context что это. картинка image loader

5. Настройка созданных бинов

Интерфейс BeanPostProcessor позволяет вклиниться в процесс настройки ваших бинов до того, как они попадут в контейнер. Интерфейс несет в себе несколько методов.

Процесс донастройки показан на рисунке ниже. Порядок в котором будут вызваны BeanPostProcessor не известен, но мы точно знаем что выполнены они будут последовательно.

Spring context что это. image loader. Spring context что это фото. Spring context что это-image loader. картинка Spring context что это. картинка image loader

Для того, что бы лучше понять для чего это нужно, давайте разберемся на каком-нибудь примере.

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

На первом этапе будет создана аннотация, которой будут помечаться поля класса, в которые нужно проинжектить значение.

По умолчанию, диапазон случайных числе будет от 0 до 10.

Затем, нужно создать обработчик этой аннотации, а именно реализацию BeanPostProcessor для обработки аннотации InjectRandomInt.

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

BeanPostProcessor обязательно должен быть бином, поэтому мы его либо помечаем аннотацией @Component, либо регестрируем его в xml конфигурации как обычный бин.

Первая группа разработчиков свою задачу выполнила. Теперь вторая группа может использовать эти наработки.

В итоге, все бины типа MyBean, получаемые из контекста, будут создаваться с уже проинициализированными полями value1 и value2. Также тут стоить отметить, этап на котором будет происходить инжект значений в эти поля будет зависеть от того какой @ Scope у вашего бина. SCOPE_SINGLETON — инициализация произойдет один раз на этапе поднятия контекста. SCOPE_PROTOTYPE — инициализация будет выполняться каждый раз по запросу. Причем во втором случае ваш бин будет проходить через все BeanPostProcessor-ы что может значительно ударить по производительности.

Полный код программы вы можете найти тут.

Хочу сказать отдельное спасибо EvgenyBorisov. Благодаря его курсу, я решился на написание этого поста.

Также советую посмотреть его доклад с JPoint 2014.

Источник

Что такое контекст Spring и как его создать?

Spring context что это. Spring Deep 8.11 5020 366d55. Spring context что это фото. Spring context что это-Spring Deep 8.11 5020 366d55. картинка Spring context что это. картинка Spring Deep 8.11 5020 366d55

Spring context что это. SPRING 1801 fefc46. Spring context что это фото. Spring context что это-SPRING 1801 fefc46. картинка Spring context что это. картинка SPRING 1801 fefc46

Контекст (а у него есть даже интерфейс — org.springframework.context.ApplicationContext ) — это некоторое окружение, в котором работает приложение на Spring Framework. Страшные аббревиатуры DI, IoC — это всё про него. Собственно, контекст создаёт и хранит экземпляры классов вашего приложения, определяет их зависимости друг с другом и автоматически их задаёт.

Безусловно, для того чтобы Spring создал контекст с экземплярами классов, ему нужно предоставить дополнительную информацию — мета-данные, из каких классов/объектов состоит ваше приложение, как они создаются, какие у них есть зависимости и т. д.

Итого: Spring Context + мета-данные = работающее приложение.

Где найти контекст?

Контекст является ключевой функциональностью Spring и лежит в maven-зависимости spring-context (на момент написания — org.springframework:spring-context:5.1.4.RELEASE ). Обычно эта зависимость является транзитивной для остальных проектов Spring. И если вы, например, подключаете spring-boot-starter, то она подключится автоматически, и не нужно думать про то, где её взять.

Но если вы хотите попробовать «голый» Spring, т. е. только ту часть, которая называется IoC-контейнер, то достаточно подключить лишь spring-context.

Какие бывают контексты и как их создать?

У интерфейса ApplicationContext есть большое количество реализаций: — ClassPathXmlApplicationContext ; — FileSystemXmlApplicationContext ; — GenericGroovyApplicationContext ; — AnnotationConfigApplicationContext ; — и даже StaticApplicationContext ; — а также некоторые другие.

Они отличаются друг от друга именно тем, каким способом задаются мета-данные и где хранится эта конфигурация. Например: — ClassPathXmlApplicationContext — метаданные конфигурируются XML-файлом(-ами) и они лежат в classpath, т. е. в ресурсах модуля; — FileSystemXmlApplicationContext — метаданные тоже конфигурируются XML-файлом(-ами), но они находятся где-то в файловой системе, например, /etc/yourapp/spring-context.xml ; — AnnotationConfigApplicationContext — метаданные конфигурируются с помощью аннотаций прямо на классах.

Современным способом конфигурирования считаются аннотации ( AnnotationConfigApplicationContext ), дальше будем создавать именно их.

Приведём пример создания такого контекста в методе main:

Итого: создаём контекст.

Следите за новостями, оставляйте комментарии и посмотрите программу курса «Разработчик на Spring Framework», вдруг захочется погрузится полностью!

Источник

Spring Context

Spring context что это. SpringDeep 10 8966 8437b5.06 Site. Spring context что это фото. Spring context что это-SpringDeep 10 8966 8437b5.06 Site. картинка Spring context что это. картинка SpringDeep 10 8966 8437b5.06 Site

Под словом «Spring» обычно подразумевают просто IoC-контейнер, помогающий структурировать Java-приложения. В действительности под словом «Spring» скрывается целый мир.

IoC-контейнер, это замечательный способ собрать приложение «по кусочкам» из разных компонентов. Spring же предоставляет удобные способы как написания данных «кусочков», так и объединения их в единое приложение. Например, у нас есть два класса.

Данные, компоненты уже достаточно неплохо. Наличие же интерфейсов мы для простоты опустим. Самый простой способ объединить эти компоненты в единое приложение – это написать что-то вроде:

Несмотря на простоту, данный код обладает серьёзными недостатками, которые являются критическими для больших проектов. Действительно, в данном примере вполне очевидно, что экземпляр класса ServiceDependency необходимо создавать раньше, чем экземпляр объекта MyService. А в больших проектах таких сервисов и зависимостей может быть столько, что перебор программистом порядка создания объектов занимал бы совсем неприличное время.

Хочется автоматического разрешения зависимостей, и чтобы даже не задумываться о создании объектов. Здесь и приходит на помощь Spring, а если быть точнее, то Spring Context. Модифицируем немного наши классы, добавив так называемые аннотации стереотипов.

И всё! Обратите внимание, что здесь не написано ни одно new наших сервисов.

Разберём подробнее

MainClass помечен аннотацией @Сonfiguration, говорящей о том, что в данном классе содержится конфигурация так называемого контекста Spring.

Как ни странно, из конфигурации в данном классе только аннотация @ComponentScan, которая говорит Spring искать все классы, помеченные Spring-аннотациями (в частности аннотациями стереотипов @Service).

Каждый класс помечен аннотацией @Service. Данные аннотация говорит Spring создать экземпляр объекта данного класса и положить его в некоторое множество таких объектов. Такие объекты, собственно, и называются beans, а множество таких объектов, соответственно, называется контекстом.

Ну и в методе main создаётся тот самый контекст: Spring автоматически определит зависимости beans друг с другом (начиная со Spring 4.0 наличие аннотации @Autowired не обязательно, если есть ровно один конструктор) и создаст экземпляры объектов в нужном порядке. Остаётся только получить экземпляр этого объекта и вызвать метод.

Данный пример, разумеется, рассматривает только один из вариантов создания beans в Spring Context. В действительности, возможностей Spring Context гораздо больше.

Есть вопрос? Напишите в комментариях!

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *