Теперь давайте разберемся с аннотациями на практике, чтобы стало понятнее.
1. Аннотация @Component — магия создания бинов
Аннотация @Component превращает обычный Java-класс в Spring Bean, который автоматически управляется IoC-контейнером Spring. Это как если бы вы поручили некому спецагенту Spring: "Следите за этим классом, создавайте его объект и внедряйте, когда потребуется".
Под капотом IoC-контейнер сканирует классы в проекте с помощью механизма Component Scan, и ищет все классы, помеченные @Component.
Пример использования @Component
import org.springframework.stereotype.Component;
// Аннотацией показываем, что этот класс — компонент (bean)
@Component
public class CoffeeMaker {
public String makeCoffee() {
return "☕ Кофе готов!";
}
}
Теперь CoffeeMaker зарегистрирован в IoC-контейнере. Вы можете получить его где угодно, и Spring сам создаст объект этого класса для вас.
Аналогия: если бы вы были Spring-контейнером, то @Component — это знак "Добавить это в список моих обязанностей".
2. Аннотация @Autowired: искусство внедрения зависимостей
Когда мы помечаем что-то аннотацией @Autowired, мы говорим Spring: "Найди и подключи нужный компонент сам!". Spring ищет подходящий бин (например, наш CoffeeMaker) и добавляет его через поле, конструктор или сеттер.
Внедрение через поле
Этот способ — самый простой, но и недостатков у него хватает (см. "Типичные ошибки" ниже).
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Barista {
// Говорим Spring: "Внедри сюда CoffeeMaker!"
@Autowired
private CoffeeMaker coffeeMaker;
public void serveCoffee() {
System.out.println(coffeeMaker.makeCoffee());
}
}
Пометив поле @Autowired, мы указали Spring, что оно должно быть инициализировано до первого вызова. Теперь, когда мы запустим приложение, Barista будет знать, как подавать кофе.
Внедрение через конструктор
Рекомендуемый способ: он делает зависимости "видимыми", да и тестировать их легко.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Barista {
private final CoffeeMaker coffeeMaker;
// Spring сам вызовет этот конструктор и передаст CoffeeMaker
@Autowired
public Barista(CoffeeMaker coffeeMaker) {
this.coffeeMaker = coffeeMaker;
}
public void serveCoffee() {
System.out.println(coffeeMaker.makeCoffee());
}
}
Внедрение через сеттер
Подходит, если зависимости можно менять в runtime (это нужно редко, но мало ли чего).
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Barista {
private CoffeeMaker coffeeMaker;
@Autowired
public void setCoffeeMaker(CoffeeMaker coffeeMaker) {
this.coffeeMaker = coffeeMaker;
}
public void serveCoffee() {
System.out.println(coffeeMaker.makeCoffee());
}
}
Совет: если зависимость обязательна, используйте конструктор. Если нет — сеттер.
3. Аннотация @Bean — создание кастомных бинов
Аннотация @Bean нужна для явного указания Spring, что метод в классе-конфигурации создает бин. Этот подход особенно полезен, если вы не можете или не хотите модифицировать исходный класс (например, если он из сторонней библиотеки).
Пример использования @Bean
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// Указываем, что этот класс — Java-конфигурация
@Configuration
public class CoffeeConfig {
// Этот метод создает объект CoffeeMaker
@Bean
public CoffeeMaker coffeeMaker() {
return new CoffeeMaker();
}
}
Теперь, вместо @Component, мы явно прописали, что класс CoffeeMaker создается через метод coffeeMaker. Spring всё равно добавит его в IoC контейнер.
4. Практическое применение всех аннотаций
Теперь давайте соберем всё вместе в небольшое приложение.
Класс 1: CoffeeMaker
import org.springframework.stereotype.Component;
@Component
public class CoffeeMaker {
public String makeCoffee() {
return "☕ Кофе готов!";
}
}
Класс 2: Barista
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
@Component
public class Barista {
private final CoffeeMaker coffeeMaker;
@Autowired
public Barista(CoffeeMaker coffeeMaker) {
this.coffeeMaker = coffeeMaker;
}
public void serveCoffee() {
System.out.println(coffeeMaker.makeCoffee());
}
}
Класс 3: CoffeeShopConfig (с использованием @Bean)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CoffeeShopConfig {
@Bean
public String coffeeRecipe() {
return "Рецепт кофе: взять кофе, добавить воды и любви!";
}
}
Основной класс для запуска
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class CoffeeShopApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(CoffeeShopApplication.class, args);
// Получаем Barista из IoC контейнера
Barista barista = context.getBean(Barista.class);
barista.serveCoffee();
// Также доступен бин с кофейным рецептом
String recipe = context.getBean(String.class);
System.out.println(recipe);
}
}
5. Типичные ошибки и как их избежать
Отсутствие бина
Если вы не пометите класс @Component или не определите метод с @Bean, Spring не добавит его в IoC контейнер. В итоге вы получите NoSuchBeanDefinitionException.
Множественные кандидаты для @Autowired
Когда Spring находит два бина одного типа, он не знает, какой использовать. Здесь помогает аннотация @Qualifier.
@Autowired
@Qualifier("specialCoffeeMaker")
private CoffeeMaker coffeeMaker;
Недоступные зависимости
Если вы пытаетесь внедрить зависимости через поле, но оно объявлено private и нет ни конструктора, ни сеттера, Spring не сможет выполнить DI. Выход очевиден: используйте либо конструкторы, либо сеттеры.
Теперь вы знаете, как работать с аннотациями @Component, @Autowired и @Bean. Эти знания составляют основу написания гибких и модульных приложений в Spring Framework. Теперь дело за практикой.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ