Главная » Spring » Внедрение ссылок на другие компоненты Spring

0

Кенни – очень талантливый музыкант и может играть практиче- ски на любых инструментах. Если инструмент реализует интерфейс Instrument, Кенни сможет извлекать из него музыку. Естественно, у Кенни есть любимый инструмент, саксофон, который определен классом Saxophone в листинге 2.6.

Листинг 2.6 Класс Saxophone реализует интерфейс Instrument

package com.springinaction.springidol;

public  class  Saxophone  implements  Instrument  { public  Saxophone()  {

}

public   void   play()   { System.out.println("TOOT TOOT TOOT");

}

}

Прежде чем позволить Кенни играть на саксофоне, необходимо объявить его компонентом Spring, как показано ниже:

<bean  id="saxophone"

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

Обратите внимание, что в классе Saxophone нет свойств, нуждаю- щихся в настройке. Следовательно, в компоненте saxophone не тре- буется использовать элемент <property>.

После объявления компонента саксофона его можно передать Кенни. Ниже представлено измененное объявление компонента kenny, где для определения свойства instrument используется прием внедрения через метод записи:

<bean  id="kenny2"

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

<property name="song" value="Jingle Bells" />

<property  name="instrument"  ref="saxophone"  />

</bean>

Теперь компонент kenny снабжен всем необходимым и Кенни го- тов к исполнению. Как и с Дюком, мы должны сообщить Кенни о начале выступления следующим Java-кодом (возможно в методе main()):

ApplicationContext  ctx  =  new  ClassPathXmlApplicationContext( "com/springinaction/springidol/spring-idol.xml");

Performer  performer  =  (Performer)  ctx.getBean("kenny"); performer.perform();

Это не тот программный код, что начнет конкурс «Spring Idol», но он даст Кенни шанс попрактиковаться. Когда он будет выполнен, на экране появится следующее:

Playing Jingle Bells : TOOT  TOOT  TOOT

Однако он иллюстрирует важное понятие. Если сравнить этот код с кодом, который заставил выступать Дюка, можно обнаружить, что они мало чем отличаются. В сущности, отличие заключается только в имени компонента. И там, и там используется один и тот же код, несмотря на то что один заставляет выступать жонглера, а другой – музыканта.

Это не столько особенность Spring, сколько преимущество ис- пользования интерфейсов. Ссылаясь на исполнителя как на объ- ект, реализующий интерфейс Performer, можно не глядя заставить выступать любого конкурсанта, будь то жонглер-декламатор или саксофонист. Именно поэтому фреймворк Spring поощряет ис- пользование интерфейсов. И, как вы наверняка успели заметить, интерфейсы рука об руку с DI обеспечивают слабую связанность объектов.

Как уже упоминалось, Кенни может играть практически на любом инструменте, при условии что он реализует интерфейс Instrument. Несмотря на то что Кенни предпочитает саксофон, можно также попросить его сыграть на фортепиано. Возьмем в качестве примера класс Piano, представленный в листинге 2.7.

Листинг 2.7. Класс Piano, реализующий интерфейс Instrument

package com.springinaction.springidol;

public class Piano implements Instrument { public  Piano()  {

}

public   void   play()   {   System.out.println("PLINK  PLINK  PLINK");

}

}

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

<bean id="piano"

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

Теперь, после объявления компонента piano, чтобы поменять ин- струмент, Кенни достаточно просто изменить объявление компонен- та kenny, как показано ниже:

<bean  id="kenny"

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

<property name="song" value="Jingle Bells" />

<property  name="instrument"  ref="piano"  />

</bean>

После внесения этих изменений Кенни будет играть на форте- пиано вместо саксофона. Однако, так как класс Instrumentalist ис- пользует свое свойство instrument только через методы интерфейса Instrument, нам не пришлось ничего менять в классе Instrumentalist, чтобы обеспечить поддержку новой реализации класса Instrument. Не- смотря на то что музыкант (Instrumentalist) способен играть и на сак- софоне (Saxophone), и на фортепиано (Piano), он не имеет тесной связи ни с тем, ни с другим инструментом. Если Кенни решит выбрать цимбалы, достаточно будет просто создать класс HammeredDulcimer и изменить свойство instrument в объявлении компонента kenny.

Внедрение внутренних компонентов

Выше было показано, что Кенни может играть и на саксофоне, и на фортепиано, и на любом другом инструменте, реализующем ин-

терфейс Instrument. Но правда также в том, что саксофон и фортепиа- но могут также использоваться любым другим музыкантом, доста- точно лишь внедрить нужный инструмент в его свойство instrument. То есть не только Кенни сможет играть на любом инструменте, но и любой другой музыкант (Instrumentalist) сможет играть, например, на саксофоне. Фактически для компонентов вполне свойственно быть совместно используемыми другими компонентами.

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

Как Java-разработчик вы, вероятно, хорошо знакомы с поняти- ем внутренних классов – классов, которые определены в пределах других классов. Аналогично и внутренние компоненты – это ком- поненты, которые определяются внутри других компонентов. Для иллюстрации рассмотрим новую конфигурацию компонента kenny, где его саксофон объявляется как внутренний компонент:

<bean  id="kenny"

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

<property name="song" value="Jingle Bells" />

<property name="instrument">

<bean  class="org.springinaction.springidol.Saxophone"  />

</property>

</bean>

Как видите, внутренний компонент определяется с помощью эле- мента <bean>, вложенного непосредственно в элемент <property> свой- ства, куда он должен быть внедрен. В данном случае будет создан объект Saxophone и внедрен в свойство instrument компонента kenny.

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

<bean  id="duke"

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

<constructor-arg  value="15"  />

<constructor-arg>

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

</constructor-arg>

</bean>

Здесь экземпляр класса Sonnet29 будет создан как внутренний ком- понент и передан в виде аргумента конструктору класса PoeticJuggler.

Обратите внимание, что внутренние компоненты не имеют атри- бута id. Нет ничего противозаконного в том, чтобы добавить атрибут id в объявление внутреннего компонента, однако в этом нет необ- ходимости, потому что к внутреннему компоненту никто и никогда не будет обращаться по имени. Это является основным недостат- ком внутренних компонентов: они не могут быть повторно исполь- зованы. Внутренние компоненты могут использоваться только для однократного внедрения, и к ним не могут обращаться другие ком- поненты.

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

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

По теме:

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