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

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

Продолжение статьи Spring. Как это работает. Часть 1

 

Создание бинов через вызов конструктора

Проблема

Необходимо создать бин в IoC контейнере Spring через вызов его конструктора, наиболее распространенного пути создания бинов. Эквивалентом является использование оператора new для создания объекта в Java. 

Решение

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

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

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

Затем создаем два подкласса продуктов, скажем Battery и Disc. У каждого из них определены свои свойства.

Для определения продуктов в контейнере создаем файл описания:

В случае, когда элемент <constructor-arg> не задан, будет вызван конструктор по умолчанию без аргументов. Затем, для каждого элемента <property> Spring установит значение через сеттеры. Описанная XML конфигурация аналогична такому куску кода:

В другом случае, если определен один или более элемент <constructor-arg>, Spring вызовет наиболее подходящий конструктор с таким же количеством аргументов

Приведенная конфигурация идентична такому коду:

Можете написать класс Main для теста продуктов путем получения их из контейнера:

Разрешение двусмысленности в конструкторах

Проблема

Когда указывается один или более аргументов для конструктора бина, Spring пытается найти подходящий конструктор в бине класса и передать аргументы для создания объекта бина. Однако, если аргументы применимы к более, чем одному конструктору, это может вызвать двусмысленность при выборе подходящего конструктора В этом случае, вызов подходящего конструктора может стать затруднительным действием для Spring. 

Решение

Можно задать атрибуты type и index для элемента <constructor-arg> для того, чтобы помочь контейнеру найти ожидаемый конструктор. 

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

Теперь добавим новый конструктор к классу SequenceGenerator с аргументами prefix  и suffix.

В этом объявлении бина можно задать один или более параметров конструктора через элементы <constructor-arg>. Spring попытается найти подходящий конструктор для этого класса и передать заданные аргументы для создания объекта. 

 

info picture Тег <constructor-arg> не поддерживает атрибута name. Поиск конструктора происходит в зависимости от порядка аргументов.

 

Для контейнера не составит труда найти подходящий конструктор для двух аргументов, поскольку у нас описан лишь один конструктор, требующий задания двух аргументов. Предположим, что надо добавить еще один конструктор в класс SequenceGenerator  с аргументами prefix и initial.

Для вызова этого конструктора необходимо сделать следующее объявление бина для передачи значений prefix  и value. 

Запуск примера даст результат

Причина такого неожиданного результата состоит в том, что был вызван первый конструктор с аргументами prefix и suffix. Это произошло по той причине, что Spring распознал оба аргумента как String и решил использовать первый подходящий конструктор, поскольку никакого приведения типов не требуется. Для задания ожидаемого типа аргументов можно установить его в атрибуте type для тега <constructor-arg>. 

Теперь добавляем еще один конструктор в класс SequenceGenerator с аргументами initial и suffix и меняем объявление бина.

Запустив приложение, получим

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


Конец
Константин Дмитриевич Ушинский утверждает, что воля наша, как и наши мускулы, крепнет от постоянно усиливающейся деятельности; не давая им упражнения, вы непременно будете иметь слабые мускулы и слабую волю.

 

Приведенная конфигурация идентична такому коду:

1 Product aaa = new Battery("AAA"2.5);
2 aaa.setRechargeable(true);
3 Product cdrw = new Disc("CD-RW"1.5);
4

 разве не Product aaa = new Battery("AAA", "2.5"); ?

а не 

 

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

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