Перейти к основному содержимому

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

· 5 мин. чтения

1. Обзор

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

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

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

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

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

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

Кроме того, аннотация <context:annotation-config> в основном используется для активации аннотаций внедрения зависимостей в 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 не может разрешить bean-компонент для связывания, он выдаст исключение .

Следовательно, он предотвращает успешный запуск контейнера 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. Автопроводная неоднозначность

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

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

5.1. Автопроводка @Qualifier

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

Во-первых, мы определим 2 bean-компонента типа 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";
}
}

Теперь давайте попробуем внедрить bean-компонент 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";
}
}

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

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

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

5.3. Автопроводка по имени

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

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

public class FooService {
@Autowired
private Formatter fooFormatter;
}

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

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

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