Главная » Spring » Использование аннотации@Autowired Spring

0

Предположим, что необходимо с помощью аннотации @Autowired обеспечить автоматическое внедрение значения в свойство instrument компонента Instrumentalist. Для этого можно аннотировать метод setInstrument(), как показано ниже:

@Autowired

public   void   setInstrument(Instrument   instrument)   { this.instrument    =    instrument;

}

Теперь можно убрать элемент <property>, связывающий свойство instrument компонента типа Instrumentalist. Когда фреймворк обна- ружит, что метод setInstrument() снабжен аннотацией @Autowired, он попытается выполнить автоматическое связывание по типу (byType).

Самая интересная особенность аннотации @Autowired состоит в том, что ее необязательно применять к методу записи. Эту аннота- цию можно применить к любому методу, чтобы обеспечить автома- тическое внедрение ссылки на компонент:

@Autowired

public  void  heresYourInstrument(Instrument  instrument)  { this.instrument   =   instrument;

}

Аннотацию @Autowired можно даже применить к конструктору:

@Autowired

public   Instrumentalist(Instrument   instrument)   { this.instrument   =   instrument;

}

При использовании с конструктором аннотация @Autowired указы- вает, что механизм автоматического связывания должен использо- вать конструктор при создании компонента, даже если в описании

компонента в конфигурационном XML-файле отсутствует элемент

<constructor-arg>.

Кроме того, аннотировать можно свойства непосредственно и во- обще избавиться от методов записи:

@Autowired

private Instrument instrument;

Как видите, ключевое слово private не является препятствием для аннотации @Autowired. Несмотря на то что свойство instrument объяв- лено частным, оно будет доступно для автоматического связывания. Неужели для аннотации @Autowired нет никаких препятствий?

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

К счастью, имеется возможность помочь аннотации @Autowired

в подобных ситуациях. Сначала посмотрим, как помочь аннотации

@Autowired в случае, когда нет ни одного подходящего компонента.

Необязательное автоматическое связывание

По умолчанию аннотация @Autowired строго требует, чтобы анно- тируемые ею свойства и параметры были связаны. Если свойство, отмеченное аннотацией @Autowired, не может быть связано с каким- либо компонентом, операция автоматического связывания терпит неудачу (с возбуждением неприятного исключения NoSuchBeanDefi- nitionException). Такое поведение, когда вместо исключения Null- PointerException во время выполнения фреймворк терпит неудачу при попытке выполнить автоматическое связывание, вполне может быть желаемым.

Но точно так же может случиться, что свойство не обязатель- но должно быть связано и значение null в нем является вполне допустимым. В этой ситуации можно определить необязательное автоматическое связывание, установив атрибут required  аннотации

@Autowired в значение false. Например:

@Autowired(required=false) private  Instrument  instrument;

Здесь фреймворк Spring попытается связать свойство instrument, но если он не найдет подходящего компонента типа Instrument, ниче- го страшного не произойдет. Свойство просто получит значение null.

Примечательно, что атрибут required можно использовать везде, где допускается использовать аннотацию @Autowired. Но когда эта ан- нотация применяется к конструкторам, только один из них может быть отмечен аннотацией @Autowired с атрибутом required, установ- ленным в значение true. Для всех остальных конструкторов анно- тации @Autowired должны иметь атрибут required со значением false. Кроме того, при наличии нескольких конструкторов, отмеченных аннотацией @Autowired, Spring будет выбирать конструктор, где боль- ше всего аргументов могут быть связаны.

Уточнение неоднозначных зависимостей

С другой стороны, проблема может быть обусловлена не отсут- ствием компонентов, а неоднозначностью выбора. Может так слу- читься, что компонентов будет слишком много (по крайней мере, два), каждый из которых одинаково пригоден для внедрения в свой- ство или параметр.

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

Чтобы помочь аннотации @Autowired выбрать требуемый компо- нент, можно добавить аннотацию @Qualifier.

Например, чтобы гарантировать, что Spring выберет гитару для компонента eddie, даже если существуют другие компоненты, кото- рые могут быть связаны с его свойством instrument, можно добавить аннотацию @Qualifier, ссылающуюся на компонент с именем guitar:

@Autowired

@Qualifier("guitar")

private Instrument instrument;

Как показано в этом примере, аннотация @Qualifier определяет, что для связывания должен использоваться компонент с идентифи- катором  guitar.

На первый взгляд может сложиться впечатление, что аннотация

@Qualifier  выполняет переход от автоматического связывания по типу к автоматическому связыванию по имени. В данном приме-

ре именно это и происходит. Но в действительности аннотация

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

Однако сузить выбор можно, не только указав идентификатор компонента. Имеется также возможность явно указать требуемый компонент. Например, предположим, что компонент guitar опреде- лен в XML-файле, как показано ниже:

<bean   class="com.springinaction.springidol.Guitar">

<qualifier  value="stringed"  />

</bean>

Здесь элемент <qualifier> квалифицирует компонент guitar как струнный (stringed) инструмент. Вместо квалификации компонента в XML-файле аннотацией @Qualifier можно также аннотировать сам класс Guitar:

@Qualifier("stringed")

public  class  Guitar  implements  Instrument  {

}

Уточнение выбора компонентов с помощью строковых идентифика- торов, будь то значение атрибута id компонента или какой-то другой квалификатор, реализуется довольно просто. Однако квалификация может принимать гораздо более сложные формы. Фактически можно даже создать свои собственные аннотации, уточняющие выбор.

Создание собственных квалификаторов

Чтобы создать собственную аннотацию, уточняющую выбор, до- статочно просто определить аннотацию, которая сама отмечена анно- тацией @Qualifier. Например, создадим аннотацию @StringedInstrument, которая будет играть роль квалификатора. Определение этой анно- тации приводится в листинге 4.1.

Листинг 4.1. Использование аннотации @Qualifier для определения собственной аннотации-квалификатора

package      com.springinaction.springidol.qualifiers; import  java.lang.annotation.ElementType;

import  java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import  java.lang.annotation.Target;

import     org.springframework.beans.factory.annotation.Qualifier;

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Qualifier

public  @interface  StringedInstrument  {

}

После определения аннотации @StringedInstrument ее можно ис- пользовать для аннотирования класса Guitar  вместо аннотации

@Qualifier:

@StringedInstrument

public  class  Guitar  implements  Instrument  {

}

А затем пометить аннотацией @StringedInstrument автоматически связываемое свойство instrument:

@Autowired

@StringedInstrument

private Instrument instrument;

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

@StringedInstrument, он будет внедрен в свойство instrument.

Когда появятся несколько компонентов с аннотацией @Stringed- Instrument, потребуется добавить дополнительное уточнение, кото- рое сузит выбор до одного компонента. Например, представьте, что помимо компонента Guitar имеется еще компонент HammeredDulcimer, так же отмеченный аннотацией @StringedInstrument. Единственное ключевое отличие между гитарой и цимбалами состоит в том, что на цимбалах играют маленькими деревянными палочками (или мо- лоточками).

Поэтому, чтобы обеспечить дополнительную квалификацию клас- са Guitar, можно определить еще одну аннотацию с именем @Strummed:

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Qualifier

public @interface Strummed {

}

Теперь аннотацию @Strummed можно добавить к свойству instrument, чтобы ограничить выбор щипковыми струнными инструментами:

@Autowired

@StringedInstrument

@Strummed

private Instrument instrument;

Если класс Guitar окажется единственным с аннотациями @Strummed и @StringedInstrument, тогда в свойство instrument будет внедрен ком- понент этого класса.

Дальше можно было бы обсудить возможность добавления таких компонентов, как Ukelele (гавайская гитара) или Mandolin (мандоли- на), но мы не можем продолжать это до бесконечности. Просто пом- ните, что в этом случае потребуется дальнейшее уточнение выбора из этих дополнительных щипковых струнных инструментов.

Применение аннотации @Autowired – это лишь один из способов, спо- собствующих уменьшению размеров конфигурационных XML-фай- лов. Но он создает зависимость от фреймворка Spring (несмотря на то что эта зависимость является всего лишь аннотацией). К счастью, Spring поддерживает также стандартные альтернативы аннотации

@Autowired. Посмотрим далее, как использовать аннотацию @Inject, определяемую спецификацией «Dependency Injection for Java».

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

По теме:

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