Керівництво до весни @Autowired

1. Огляд

Починаючи з Spring 2.5, фреймворк запровадив ін’єкцію залежностей, керовану анотаціями . Основна анотація цієї функції - @Autowired . Це дозволяє Весні вирішувати та вводити зерна, що співпрацюють, у наш боб.

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

2. Увімкнення @Autowired Анотацій

Фреймворк Spring дозволяє автоматично вводити залежності. Іншими словами, оголошуючи всі залежності компонента у файлі конфігурації Spring, контейнер 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 і дозволить нам вводити зерна за допомогою @Autowired .

3. Використання @Autowired

Увімкнувши введення анотацій, ми можемо використовувати автоматичне підключення властивостей, сетерів та конструкторів .

3.1. @Autowired на Властивості

Давайте подивимося, як ми можемо коментувати властивість за допомогою @Autowired . Це позбавляє потреби в геттерах і сеттерах.

Спочатку визначимо beo fooFormatter :

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

Потім ми введемо цей компонент у компонент FooService, використовуючи @Autowired у визначенні поля:

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

В результаті Spring створює fooFormatter, коли створюється FooService .

3.2. @Autowired on Setters

Тепер спробуємо додати анотацію @Autowired для методу встановлення.

У наступному прикладі метод сетера викликається з екземпляром FooFormatter, коли створюється FooService :

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

3.3. @Autowired on Constructors

Нарешті, давайте використаємо @Autowired на конструкторі.

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

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

4. Автозалежні та необов’язкові залежності

Коли будується компонент, повинні бути доступні залежності @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)}

Щоб це виправити, нам потрібно оголосити компонент необхідного типу:

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

5. Автоматичне роз’єднання значень проводів

За замовчуванням Spring вирішує записи @Autowired за типом. Якщо в контейнері є більше одного компонента одного типу, фреймворк видасть фатальне виняток .

Щоб вирішити цей конфлікт, нам потрібно чітко сказати Spring, який бін ми хочемо ввести.

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

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

Спочатку визначимо 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; }

Коли є кілька різновидів одного типу, рекомендується використовувати @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 використовує ім'я компонента як значення кваліфікатора за замовчуванням. Він огляне контейнер і шукає боб з точною назвою як властивість для його автоматичного підключення.

Hence, in our example, Spring matches the fooFormatter property name to the FooFormatter implementation. Therefore, it injects that specific implementation when constructing FooService:

public class FooService { @Autowired private Formatter fooFormatter; }

6. Conclusion

In this article, we discussed autowiring and the different ways to use it. We also examined ways to solve two common autowiring exceptions caused by either a missing bean or an ambiguous bean injection.

The source code of this article is available on the GitHub project.