spring что такое application context
Spring ApplicationContext
Узнайте об интерфейсе ApplicationContext в Spring и о том, как настроить компоненты в некоторых наиболее распространенных типах ApplicationContext.
1. Обзор
2. Интерфейс ApplicationContext
Одной из основных особенностей пружинного каркаса является контейнер IoC (Инверсия управления). Контейнер Spring IoC отвечает за управление объектами приложения. Он использует инъекцию зависимостей для достижения инверсии управления.
3. Что такое Весенняя Фасоль?
Итак, должны ли мы настроить все объекты нашего приложения как Spring beans? Ну, как лучшая практика, мы не должны этого делать.
Кроме того, как правило, мы не должны настраивать мелкозернистые объекты домена в контейнере. Обычно ответственность за создание и загрузку объектов домена лежит на DAO и бизнес-логике.
Итак, давайте определим простой класс Java, который мы будем использовать в качестве компонента Spring в этом уроке:
4. Настройка бобов в контейнере
Как мы знаем, основная задача ApplicationContext заключается в управлении бобами.
4.1. Конфигурация на основе Java
Во-первых, мы начнем с конфигурации на основе Java, поскольку это самый новый и наиболее предпочтительный способ настройки компонентов. Он доступен с весны 3.0 и далее.
Конфигурация Java обычно использует @Bean -аннотированные методы в классе @Configuration . Аннотация @Bean в методе указывает, что метод создает пружинный компонент. Кроме того, класс с аннотацией @Configuration указывает, что он содержит конфигурации компонентов Spring.
Итак, давайте теперь создадим класс конфигурации, чтобы определить наш Account Service класс как Spring bean:
4.2. Конфигурация на основе аннотаций
Spring 2.5 представила конфигурацию на основе аннотаций в качестве первого шага для включения конфигураций компонентов в Java.
Примечательно, что мы также используем эти аннотации с конфигурацией на основе Java. Кроме того, Spring продолжает добавлять новые возможности к этим аннотациям с каждым выпуском.
Итак, теперь давайте рассмотрим простой пример этой конфигурации.
Во-вторых, мы создадим класс User Service и определим его как Spring bean, используя аннотацию @Component :
А затем мы напишем простой тестовый случай для проверки этой конфигурации:
4.3. Конфигурация на основе XML
Наконец, давайте рассмотрим конфигурацию на основе XML. Это традиционный способ настройки бобов весной.
5. Типы ApplicationContext
5.1. Аннотацияconfigapplicationcontext
Итак, давайте рассмотрим простой пример использования контейнера AnnotationConfigApplicationContext с нашей конфигурацией на основе Java:
5.2. аннотацияconfigwebapplicationcontext
Мы можем использовать этот класс при настройке прослушивателя Spring ContextLoaderListener servlet или Spring MVC DispatcherServlet в web.xml файл.
Кроме того, начиная с Spring 3.0 и далее, мы также можем программно настроить этот контейнер контекста приложения. Все, что нам нужно сделать, это реализовать интерфейс WebApplicationInitializer :
5.3. XmlWebApplicationContext
5.4. Файловая система xmlapplicationcontext
Например, давайте посмотрим, как мы можем создать этот контейнер Spring и загрузить компоненты для нашей конфигурации на основе XML:
5.5. ClassPathXmlApplicationContext
Итак, давайте рассмотрим пример использования этого класса:
6. Дополнительные возможности ApplicationContext
6.1. Разрешение сообщений
Мы можем использовать StaticMessageSource для программного добавления сообщений в источник. Однако он поддерживает базовую интернационализацию и больше подходит для тестов, чем для производственного использования.
Теперь давайте посмотрим, как мы можем использовать Источник сообщений для чтения сообщений из файла свойств.
Сначала мы создадим файл messages.properties в пути к классу:
Во-вторых, мы добавим определение компонента в наш класс Account Config :
В-третьих, мы введем MessageSource в службу учетных записей :
Наконец, мы можем использовать метод GetMessage в любом месте службы Account для чтения сообщения:
6.2. Обработка событий
7. Заключение
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.
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 – ApplicationContext
Note: It is because of these additional features, developers prefer to use ApplicationContext over BeanFactory.
Attention reader! Don’t stop learning now. Get hold of all the important Java Foundation and Collections concepts with the Fundamentals of Java and Java Collections Course at a student-friendly price and become industry ready. To complete your preparation from learning a language to DS Algo and many more, please refer Complete Interview Preparation Course.
ApplicationContext Implementation Classes
There are different types of Application containers provided by Spring for different requirements as listed below which later onwards are described alongside with declaration, at lastly providing an example to get through the implementation part with the pictorial aids. Containers are as follows:
Container 1: AnnotationConfigApplicationContext
AnnotationConfigApplicationContext class was introduced in Spring 3.0. It accepts classes annotated with @Configuration, @Component, and JSR-330 compliant classes. The constructor of AnnotationConfigApplicationContext accepts one or more classes. For example, in the below declaration, two Configuration classes Appconfig and AppConfig1 are passed as arguments to the constructor. The beans defined in later classes will override the same type and name beans in earlier classes when passed as arguments. For example, AppConfig and AppConfig1 have the same bean declaration. The bean defined in AppConfig1 overrides the bean in AppConfig.
Syntax: Declaration
Note: Add the following to the properties file in the IDE to allow the spring to override beans.
Container 2: AnnotationConfigWebApplicationContext
AnnotationConfigWebApplicationContext class was introduced in Spring 3.0. It is similar to AnnotationConfigApplicationContext for a web environment. It accepts classes annotated with @Configuration, @Component, and JSR-330 compliant classes. These classes can be registered via register() method or passing base packages to scan() method. This class may be used when we configure ContextLoaderListener servlet listener or a DispatcherServlet in a web.xml. From Spring 3.1, this class can be instantiated and injected to DispatcherServlet using java code by implementing WebApplicationInitializer, an alternative to web.xml.
Example
Container 3: XmlWebApplicationContext
Spring MVC Web-based application can be configured completely using XML or Java code. Configuring this container is similar to the AnnotationConfigWebApplicationContext container, which implies we can configure it in web.xml or using java code.
Container 4: FileSystemXmlApplicationContext
FileSystemXmlApplicationContext is used to load XML-based Spring Configuration files from the file system or from URL. We can get the application context using Java code. It is useful for standalone environments and test harnesses. The following code shows how to create a container and use the XML as metadata information to load the beans.
Illustration:
Container 5: ClassPathXmlApplicationContext
FileSystemXmlApplicationContext is used to load XML-based Spring Configuration files from the classpath. We can get the application context using Java code. It is useful for standalone environments and test harnesses. The following code shows how to create a container and use the XML as metadata information to load the beans.
Illustration:
Now, let us implement the same showcasing an example which is as follows:
Example
Step 1: Creating a Spring Project using Spring Initializer as pictorially depicted below.
Step 3: Now the Main Application class at the root contains the creation of a container.
Подготовка к 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.
Как обычно, просьба присылать правки или найденные ошибки в личку.