Главная » Spring » Внедрение через конструкторы Spring

0

Чтобы действительно удивить судей, Дюк решает побить мировой рекорд, жонглируя не меньше чем 15 мячиками одновременно2.

1   Обратите внимание на слова «по сути». В действительности фреймворк Spring создает компоненты, используя механизм рефлексии.

2   Дополнительная информация: чтобы установить мировой рекорд по жонг- лированию мячиками, нужно не только уметь жонглировать большим их количеством, но и жонглировать достаточно долго. Несколько мировых рекордов принадлежит Брюсу Сарафьяну (Bruce Sarafian), в том числе

Как было показано в листинге 2.1, класс Juggler может быть соз- дан двумя разными способами:

# вызовом конструктора по умолчанию;

# вызовом конструктора с аргументом типа int, определяющим количество мячиков, которые жонглер Juggler должен попы- таться удержать в воздухе.

Объявление компонента duke в разделе 2.1.2 выполнено правиль- но, но в нем используется конструктор по умолчанию класса Juggler, что позволяет Дюку жонглировать только тремя мячиками. Чтобы сделать Дюка рекордсменом по жонглированию, необходимо ис- пользовать другой конструктор. Ниже показано иное объявление Дюка как жонглера 15 мячиками:

<bean  id="duke"

class="com.springinaction.springidol.Juggler">

<constructor-arg  value="15"  />

</bean>

Элемент <constructor-arg> здесь используется для передачи фрейм- ворку Spring дополнительной информации, касающейся создания компонента. Если элемент <constructor-arg> не указан, как в разде- ле 2.1.2, будет использоваться конструктор по умолчанию. Но здесь присутствует элемент <constructor-arg> со значением 15 в атрибуте value, поэтому фреймворк задействует другой конструктор.

Теперь при выступлении Дюка будет выведено следующее:

JUGGLING   15   BEANBAGS

Жонглирование 15 мячиками одновременно должно выглядеть весьма впечатляюще. Но Дюк – не только хороший жонглер, но еще и искусный декламатор. Чтобы научиться жонглировать и одновре- менно декламировать стихи, необходимо много тренироваться. Если Дюк сможет жонглировать и одновременно читать сонеты Шекспи- ра, он наверняка сможет стать абсолютным победителем конкурса. (Я предупреждал, что это будет необычный конкурс!)

жонглирование 12 мячиками до 12 поимок. Другой рекордсмен, Энтони Гато (Anthony Gatto), в 2005 году установил рекорд, жонглируя 7 мя- чиками в течение 10 минут и 12 секунд. Еще один жонглер, Питер Бон (Peter Bone), заявил, что жонглировал 13 мячиками до 13 поимок, но не представил видеозаписи, доказывающей это достижение.

Внедрение ссылок через конструкторы

Так как Дюк – не обычный жонглер, а поэтический жонглер, необ- ходимо определить для него новый тип жонглера. Класс PoeticJuggler (листинг 2.2) точнее описывает таланты Дюка.

Листинг 2.2. Жонглер, декламирующий стихи

package com.springinaction.springidol;

public   class   PoeticJuggler   extends   Juggler   { private Poem poem;

public PoeticJuggler(Poem poem) { // Внедрение поэмы super();

this.poem  =  poem;

}

public  PoeticJuggler(int  beanBags,  Poem  poem)  {    // Внедрение  количества super(beanBags);                                                   // мячиков  и  поэмы this.poem = poem;

}

public  void  perform()  throws  PerformanceException  { super.perform();

System.out.println("While reciting…"); poem.recite();

}

}

Этот новый тип жонглера делает все то же, что и обычный жонг- лер, но также содержит ссылку на декламируемую им поэму. Коль скоро речь зашла о поэме, необходимо определить интерфейс, кото- рый описывает поэму:

package   com.springinaction.springidol; public interface Poem {

void recite();

}

Один из любимых сонетов Дюка – сонет Шекспира «Когда в раз- доре с миром и судьбой»1. Класс Sonnet29 (листинг 2.3) реализует интерфейс Poem, определяющий этот сонет.

1   Сонет 29 в переводе С. Я. Маршака. – Прим. перев.

Листинг 2.3. Класс, олицетворяющий выдающееся произведение поэта

package      com.springinaction.springidol; public class  Sonnet29 implements  Poem  {

private  static  String[]  LINES  =  {

"Когда  в  раздоре  с  миром  и  судьбой,", "Припомнив  годы,  полные  невзгод,", "Тревожу  я  бесплодною  мольбой", "Глухой  и  равнодушный  небосвод",

"И,  жалуясь  на  горестный  удел,", "Готов меняться жребием своим",

"С  тем,  кто  в  искусстве  больше  преуспел,", "Богат надеждой и людьми любим, -",  "Тогда,  внезапно  вспомнив  о  тебе,",

"Я  малодушье  жалкое  кляну,",

"И   жаворонком,   вопреки   судьбе,", "Моя  душа  несется  в  вышину.",

"С твоей любовью, с памятью о ней", "Всех  королей  на  свете  я  сильней."};

public  Sonnet29()  {

}

public  void  recite()  {

for (int i = 0; i < LINES.length; i++) { System.out.println(LINES[i]);

}

}

}

Объект класса Sonnet29 можно объявить компонентом Spring, как показано ниже:

<bean id="sonnet29"

class="com.springinaction.springidol.Sonnet29"   />

Осталось только передать выбранную поэму Дюку. Теперь, ког- да Дюк стал поэтическим жонглером (PoeticJuggler), его описание в элементе <bean> следует немного изменить:

<bean id="poeticDuke" class="com.springinaction.springidol.PoeticJuggler">

<constructor-arg  value="15"  />

<constructor-arg  ref="sonnet29"  />

</bean>

Как показано в листинге 2.2, в этом классе отсутствует конструк- тор по умолчанию. Единственный способ создать объект PoeticJuggler заключается в том, чтобы использовать конструктор с аргументами. В этом примере используется конструктор, принимающий аргу- менты типов int и Poem. В объявлении компонента duke, с помощью атрибута value элемента <constructor-arg>, указывается количество мячиков, равное 15.

Однако использовать атрибут value для инициализации второго аргумента конструктора нельзя, потому что Poem не является прос- тым типом. Для передачи ссылок на другие компоненты следует ис- пользовать атрибут ref. В данном случае это должна быть ссылка на компонент с идентификатором sonnet29. Контейнер Spring – это не просто механизм создания компонентов. Когда фреймворк Spring встречает определения компонентов sonnet29 и duke, он выполняет дополнительные действия, которые можно выразить следующим программным кодом:

Poem   sonnet29   =   new   Sonnet29();

Performer   duke   =   new   PoeticJuggler(15,   sonnet29);

Теперь, когда начнется выступление Дюка, он не только будет жонглировать мячиками, но и прочитает сонет Шекспира, в резуль- тате на экран будет выведено следующее:

JUGGLING 15 BEANBAGS WHILE RECITING… Когда в раздоре с миром и судьбой,   Припомнив годы, полные невзгод, Тревожу я бесплодною мольбой Глухой и равнодушный небосвод  И,  жалуясь  на  горестный  удел,  Готов  меняться  жребием  своим  С  тем,  кто  в искусстве  больше  преуспел,  Богат  надеждой  и  людьми  любим,  –  Тогда,  внезапно  вспом- нив  о  тебе,  Я  малодушье  жалкое  кляну,  И  жаворонком,  вопреки  судьбе,  Моя  душа  не- сется  в  вышину.  С  твоей  любовью,  с  памятью  о  ней  Всех  королей  на  свете  я  сильней.

Создание компонентов с применением приема внедрения через конструктор – надежный способ, но как быть, если компонент, ко- торый требуется объявить, не имеет общедоступного конструктора? Посмотрим, как реализуется связывание компонентов, создаваемых с помощью фабричных методов.

Создание компонентов с помощью фабричных методов

Иногда единственный способ создать объект заключается в том, чтобы использовать статический фабричный метод. Фреймворк Spring

поддерживает возможность связывания компонентов, объявленных с помощью элементов <bean>, которые содержат атрибут factory-method.

Для иллюстрации рассмотрим порядок определения компонен- та, являющегося экземпляром класса-одиночки1. Классы-одиноч- ки гарантируют возможность создания только одного экземпляра. Типичным примером класса-одиночки может служить класс Stage, представленный в листинге 2.4 ниже.

Листинг 2.4. Класс-одиночка Stage

package com.springinaction.springidol;

public  class  Stage  { private  Stage()  {

}

private static class StageSingletonHolder {

static Stage instance = new Stage(); // Создание экземпляра

}

public  static  Stage  getInstance()  {

return StageSingletonHolder.instance; // Возвращает экземпляр

}

}

В конкурсе «Spring Idol» необходимо гарантировать наличие толь- ко одной сцены для выступлений. Класс Stage реализован с примене- нием шаблона проектирования «Одиночка» (Singleton), чтобы устра- нить любые возможности создания более одного его экземпляра.

Однако заметьте, что класс Stage не имеет общедоступного конст- руктора. Вместо него используется статический метод getInstance(), который каждый раз возвращает один и тот же экземпляр класса. (Для безопасности при выполнении в многопоточной среде созда- ние экземпляра класса в методе getInstance() выполняется с исполь- зованием приема, известного как «инициализация по требованию владельца»2.) Как же превратить объект Stage, не имеющий обще- доступного конструктора, в компонент Spring?

1   Здесь имеется в виду шаблон проектирования «Одиночка» (Singleton), представленный «бандой четырех», а не понятие определения единичного компонента, существующее в Spring.

2   Дополнительную информацию об идиоме «инициализация по требова- нию владельца» можно найти по адресу: http://mng.bz/IGYx.

К счастью, элемент <bean> имеет атрибут factory-method, позво- ляющий определить статический метод, который должен вызы- ваться для создания экземпляра  класса вместо конструктора. Чтобы превратить объект Stage в компонент в контексте Spring, достаточно просто воспользоваться атрибутом factory-method, как показано ниже:

<bean  id="theStage"

class="com.springinaction.springidol.Stage" factory-method="getInstance" />

Здесь я показал, как использовать атрибут factory-method для созда- ния экземпляра класса-одиночки и преобразования его в компонент Spring, но этот прием подходит для любых случаев, где необходимо связать объект, создаваемый статическим методом. Дополнительные примеры использования атрибута factory-method будут представлены в главе 5, где он будет использоваться для получения ссылок на аспекты AspectJ перед их внедрением в зависимости.

Источник:   Уоллс К., Spring в действии. – М.: ДМК Пресс, 2013. – 752 с.: ил.

По теме:

  • Комментарии