Spring. Как это работает? Часть 3

max аватар
95
Находится в разделах:

Продолжение статьи Spring. Как это работает? Часть 2: Создание бинов через вызов конструктора

 

Определение ссылок на бины / Specifying Bean References

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

Решение

В конфигурационном файле можно задать ссылку на бин для свойства бина или аргумента конструктора с использованием элемента <ref>. Это так же просто, как и задание значений через элемент <value>. Можно также задать объявление бина в свойстве или аргументе конструктора в виде вложенного бина. 

Как это работает

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

Одна из стратегий генерации префикса заключается в использовании определенного шаблона для формирования текущего системного времени. Создадим класс DatePrefixGenerator, который будет реализовать интерфейс PrefixGenerator.

Шаблон генератора будет вставлен через сеттер setPattern(), а затем использован для создания объекта java.text.DateFormat для формирования даты. Поскольку строка шаблона станет бесполезной как только будет создан объект DateFormat, нет необходимости хранить ее в виде приватного поля.

Теперь можно объявить бин типа DatePrefixGenerator с произвольным шаблоном для форматирования даты.

Определение ссылок на бины для сеттеров

Для применения такого подхода для генерации префиксов, класс SequenceGenerator должен принимать объект типа PrefixGenerator вместо обычного строкового префикса. Можно выбрать инъекцию через сеттеры. Для этого надо удалить свойство prefix, что вызовет ошибки компиляции.

Затем, бин SequenceGenerator может ссылаться на datePrefixGenerator и его свойство prefixGenerator с помощью тега <ref>.

Имя бина в элементе <ref> может быть ссылкой на любой бин в контейнере, даже если он не определен в этом же конфигурационном файле. Если вы ссылаетесь на бин из того же файла, необходимо использовать атрибут local.

 

Есть также возможность объявить ссылку на бин в ref атрибуте элемента <property>.

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

 

Определение ссылок на бины через аргументы конструктора

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

В элементе <constructor-arg> можно объявить ссылку на бин через <ref> 

Ярлык для определения ссылки на бин работает также для <constructor-arg>.

Объявление вложенных бинов

В случаях, когда объект бина используется только для одного определенного свойства, он может быть объявлен в виде вложенного бина. Декларация вложенного бина задается в теге <property> или <constructor-arg> напрямую, без всяких id или name атрибутов. В таком случае, бин будет анонимным, поэтому его больше нигде нельзя будет использовать. 

Вложенный бин может также быть объявлен в виде аргумента конструктора

Определение типа данных для коллекций

По умолчанию, Spring интерпретирует все элементы коллекции в виде строк. Если мы собираемся использовать типы данных, отличные от строковых, необходимо их давать в объявлении.

Для этого можно либо определить тип данных для каждого элемента коллекции с использованием атрибута type тега <value>, либо определить тип данных для всех элементов в атрибуте value-type тега коллекции.

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

Затем объявим несколько суффиксов для генератора последовательностей в конфигурации бина.

Однако, при запуске приложения мы получим ClassCastException. Это говорит о том, что суффиксы не могут быть приведены к целочисленным значениям, поскольку они объявлены как String. 

 

info picture По умолчанию, Spring воспринимает все элементы коллекции как String.

 

Чтобы задать тип элемента, необходимо задать тип атрибута в теге <value>.

Можно также задать атрибут value-type тега коллекции, чтобы указать тип для всех элементов сразу.

Создание бинов с помощью FactoryBean

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

Основные требования к фабричному методу - реализовать интерфейс FactoryBean. Для удобства, Spring предоставляет абстрактный шаблонный класс, AbstractFactoryBean, от которого можно наследоваться. Фабричные бины в своем большинстве, используются для реализации поведения фреймворка. Вот несколько примеров:

  • Можно использовать JndiObjectFactoryBean в тех случаях, когда необходимо получить объект через JNDI (например соединение с базой данных)
  • Можно использовать ProxyFactoryBean в тех случаях, если необходимо создать прокси для бина при использолвании Spring AOP.
  • При создании фабрики соединений Hibernate в контейнере можно использовать LocalSessionFactoryBean.
Однако, как пользователь фреймворка, Вы редко захотите писать собственные фабричные бины, поскольку они специфичны и не могут быть использованы вне области действия контейнера. 
Хоть Вы и редко будете писать свои фабричные бины, Вам может пригодиться понимание их внутренних механизмов. Например, можем написать фабричный бин для создания продукта со скидкой относительно его цены. Он будет принимать на вход свойство product и свойство discount для вычисления скидки по продукту и возвращения результата в виде нового бина. 
Наследуясь от класса AbstractFactoryBean, просто переопределим метод createInstance() для создания объекта целевого бина. В дополнение, необходимо возвращать тип целевого бина в методе getObjectType() для автоматического связывания.
Далее, необходимо объявить объекты продуктов с DiscountFactoryBean. Каждый раз, когда мы будем запрашивать бин, который реализует интерфейс FactoryBean, контейнер будет использовать этот фабричный бин для создания целевого бина и его возвращения. 
Конфигурация фабричного бина делает то же, что и следующий кусок кода:

Конец
Джордж Бернард Шоу хочет заметить, что единственный способ что-то узнать — это что-то делать.

Огромное спасибо за весь материал по Spring. Без вас убили бы гораздо больше времени на перевод документации

Отправить комментарий

CAPTCHA
Чтобы оставить комментарий, введите пожалуйста код, изображенный на картинке
Image CAPTCHA
Введите символы, изображенные на картинке