Руководство по Spring @Autowired

1. Обзор

Начиная с Spring 2.5, фреймворк представил внедрение зависимостей на основе аннотаций . Основная аннотация этой функции - @Autowired . Это позволяет Spring разрешать и внедрять сотрудничающие bean-компоненты в наш bean-компонент.

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

2. Включение аннотаций @Autowired

Фреймворк Spring обеспечивает автоматическое внедрение зависимостей. Другими словами, объявляя все зависимости bean-компонентов в файле конфигурации Spring, контейнер Spring может автоматически устанавливать связи между сотрудничающими bean-компонентами . Это называется автоматическим подключением компонентов Spring .

Чтобы использовать конфигурацию на основе Java в нашем приложении, давайте включим инъекцию на основе аннотацийчтобы загрузить нашу конфигурацию Spring:

@Configuration @ComponentScan("com.baeldung.autowire.sample") public class AppConfig {}

В качестве альтернативы Аннотации в основном используются для активации аннотаций внедрения зависимостей в XML-файлах Spring.

Кроме того, Spring Boot представляет аннотацию @SpringBootApplication . Эта единственная аннотация эквивалентна использованию @Configuration , @EnableAutoConfiguration и @ComponentScan .

Воспользуемся этой аннотацией в основном классе приложения:

@SpringBootApplication class VehicleFactoryApplication { public static void main(String[] args) { SpringApplication.run(VehicleFactoryApplication.class, args); } }

В результате, когда мы запускаем это приложение Spring Boot, оно автоматически сканирует компоненты в текущем пакете и его подпакетах . Таким образом, он зарегистрирует их в контексте приложения Spring и позволит нам внедрять bean-компоненты с помощью @Autowired .

3. Использование @Autowired

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

3.1. @Autowired в свойствах

Давайте посмотрим, как мы можем аннотировать свойство с помощью @Autowired . Это устраняет необходимость в геттерах и сеттерах.

Сначала давайте определим bean- компонент fooFormatter :

@Component("fooFormatter") public class FooFormatter { public String format() { return "foo"; } }

Затем мы внедрим этот bean-компонент в bean- компонент FooService, используя @Autowired в определении поля:

@Component public class FooService { @Autowired private FooFormatter fooFormatter; }

В результате Spring внедряет fooFormatter при создании FooService .

3.2. @Autowired на сеттерах

Теперь попробуем добавить аннотацию @Autowired в метод установки.

В следующем примере метод установки вызывается с экземпляром FooFormatter при создании FooService :

public class FooService { private FooFormatter fooFormatter; @Autowired public void setFooFormatter(FooFormatter fooFormatter) { this.fooFormatter = fooFormatter; } } 

3.3. @Autowired на конструкторах

Наконец, давайте используем @Autowired в конструкторе.

Мы увидим, что экземпляр FooFormatter внедряется Spring в качестве аргумента конструктору FooService :

public class FooService { private FooFormatter fooFormatter; @Autowired public FooService(FooFormatter fooFormatter) { this.fooFormatter = fooFormatter; } }

4. @Autowired и дополнительные зависимости

При создании bean-компонента должны быть доступны зависимости @Autowired . В противном случае, если Spring не может разрешить компонент для подключения, он выдаст исключение .

Следовательно, он препятствует успешному запуску контейнера Spring, за исключением формы:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.autowire.sample.FooDAO] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

Чтобы исправить это, нам нужно объявить bean-компонент требуемого типа:

public class FooService { @Autowired(required = false) private FooDAO dataAccessor; }

5. Устранение неоднозначности Autowire

По умолчанию Spring разрешает записи @Autowired по типу. Если в контейнере доступно более одного bean-компонента одного типа, инфраструктура выдаст фатальное исключение .

Чтобы разрешить этот конфликт, нам нужно явно указать Spring, какой bean-компонент мы хотим внедрить.

5.1. Автоподключение от @Qualifier

Например, давайте посмотрим, как мы можем использовать аннотацию @Qualifier для указания необходимого bean-компонента.

Сначала мы определим 2 компонента типа Formatter :

@Component("fooFormatter") public class FooFormatter implements Formatter { public String format() { return "foo"; } }
@Component("barFormatter") public class BarFormatter implements Formatter { public String format() { return "bar"; } }

Теперь давайте попробуем придать Formatter боб в FooService класса:

public class FooService { @Autowired private Formatter formatter; }

В нашем примере для контейнера Spring доступны две конкретные реализации Formatter . В результате Spring вызовет исключение NoUniqueBeanDefinitionException при создании FooService :

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.autowire.sample.Formatter] is defined: expected single matching bean but found 2: barFormatter,fooFormatter 

Этого можно избежать, сузив реализацию с помощью аннотации @Qualifier :

public class FooService { @Autowired @Qualifier("fooFormatter") private Formatter formatter; }

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

Пожалуйста , обратите внимание , что стоимость @Qualifier аннотаций спичек с именем объявлено в @Component аннотации нашего FooFormatter реализации.

5.2. Автоматическое подключение по специальному квалификатору

Spring также позволяет нам создавать нашу собственную аннотацию @Qualifier . Для этого мы должны предоставить аннотацию @Qualifier с определением:

@Qualifier @Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) public @interface FormatterType { String value(); }

Затем мы можем использовать FormatterType в различных реализациях, чтобы указать настраиваемое значение:

@FormatterType("Foo") @Component public class FooFormatter implements Formatter { public String format() { return "foo"; } }
@FormatterType("Bar") @Component public class BarFormatter implements Formatter { public String format() { return "bar"; } }

Наконец, наша специальная аннотация Qualifier готова к использованию для автоматического подключения:

@Component public class FooService { @Autowired @FormatterType("Foo") private Formatter formatter; } 

Значение, указанное в метааннотации @Target, ограничивает место применения квалификатора, которым в нашем примере являются поля, методы, типы и параметры.

5.3. Автоподключение по имени

Spring использует имя bean-компонента в качестве значения квалификатора по умолчанию. Он будет проверять контейнер и искать bean-компонент с точным именем в качестве свойства для его автосоединения.

Следовательно, в нашем примере Spring сопоставляет имя свойства fooFormatter с реализацией FooFormatter . Следовательно, он внедряет эту конкретную реализацию при создании FooService :

public class FooService { @Autowired private Formatter fooFormatter; }

6. Заключение

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

Исходный код этой статьи доступен в проекте GitHub.