JavaRush /Курсы /Модуль 5. Spring /Практика: аннотации @Component, @Autowired, @Bean

Практика: аннотации @Component, @Autowired, @Bean

Модуль 5. Spring
2 уровень , 4 лекция
Открыта

Теперь давайте разберемся с аннотациями на практике, чтобы стало понятнее.

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. Теперь дело за практикой.

Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ