JavaRush /Курсы /Модуль 5. Spring /Практика: создание конфигурационных классов и бинов

Практика: создание конфигурационных классов и бинов

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

Конфигурационные классы в Java заменяют старый подход с XML-конфигурацией. Тем самым они превращают настройку Spring-приложений в более читаемый и удобный процесс.

Конфигурационный класс — это Java-класс, который используется для описания конфигурации вашего приложения. В Spring такие классы помечают аннотацией @Configuration. Это даёт понять IoC-контейнеру, что класс содержит методы, которые создают бины. Эти методы помечаются аннотацией @Bean.

Конфигурационный класс можно представить как меню вашего любимого кафе. С помощью @Bean вы описываете, что будет подано на стол (объекты), а IoC-контейнер выступает официантом, который доставит всё нужное (внедрение зависимостей) на ваш столик.

Пример простого конфигурационного класса


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public String welcomeMessage() {
        return "Добро пожаловать в Spring Framework!";
    }
}

В нашем примере welcomeMessage — это бин, который возвращает строку. Конфигурационный класс AppConfig содержит метод, помеченный аннотацией @Bean, а Spring знает, что этот метод создаёт бин, управляемый IoC-контейнером.

Но не волнуйтесь, мы не будем останавливаться на бине, который просто говорит вам "привет". Мы ещё разгонимся и создадим более сложные конфигурации.


Создание бинов и работа с зависимостями

Конфигурационные классы полезны при создании объектов, у которых есть зависимости. Например, если у нас есть класс Car, и он зависит от двигателя Engine, мы можем настроить это в конфигурационном классе.

Пример с зависимостями


public class Engine {
    private String type;

    public Engine(String type) {
        this.type = type;
    }

    public String getType() {
        return type;
    }
}

public class Car {
    private Engine engine;

    public Car(Engine engine) {
        this.engine = engine;
    }

    public void drive() {
        System.out.println("Car is driving with " + engine.getType() + " engine.");
    }
}

Теперь создадим конфигурационный класс для этих объектов:


@Configuration
public class VehicleConfig {

    @Bean
    public Engine engine() {
        return new Engine("V8");
    }

    @Bean
    public Car car() {
        return new Car(engine());
    }
}

В методе car мы вызываем метод engine, чтобы передать его в конструктор класса Car. Это позволяет Spring понять, что бин Car зависит от бина Engine. Теперь IoC-контейнер позаботится о том, чтобы правильно настроить наш объект.

Как это работает?

  1. Spring создаёт бин Engine с типом V8.
  2. Затем создаётся бин Car, и в его конструктор автоматически передаётся бин Engine.

Этот удобный процесс сокращает количество кода, который мы писали бы вручную. Согласитесь, мало кого бы обрадовало создание всех зависимостей руками.

Декларация зависимостей между бинами в явной форме

Если по каким-то причинам вы захотите явно указать бину Car, что ему нужен бин Engine, это можно сделать с аннотацией @Qualifier (спойлер: понадобится в следующих лекциях).


Сложные зависимости: бины, зависящие от нескольких других бинов

Допустим, мы создаём сервис бронирования авиабилетов. Нам нужно объединить несколько зависимостей, таких, как клиент для работы с базой данных и сервис оплаты. Всё это можно настроить в конфигурационном классе.


public class PaymentService {
    public void pay() {
        System.out.println("Платёж успешно обработан!");
    }
}

public class BookingService {
    private PaymentService paymentService;

    public BookingService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }

    public void bookFlight() {
        System.out.println("Бронирование завершено.");
        paymentService.pay();
    }
}

Настроим всё это с помощью конфигурационного класса:


@Configuration
public class BookingConfig {

    @Bean
    public PaymentService paymentService() {
        return new PaymentService();
    }

    @Bean
    public BookingService bookingService() {
        return new BookingService(paymentService());
    }
}

Теперь мы получили:

  • Инкапсуляцию логики создания объектов.
  • Минимизацию кода в основной логике приложения.
  • Гибкость: изменения в конфигурации легко адаптируются.

Предотвращаем проблемы с дублированием бинов

Одной из распространённых ошибок является случайное создание дубликатов бинов. Если вы попытаетесь объявить два бина с одинаковым именем, Spring выдаст ошибку: "Найдено несколько кандидатов для внедрения зависимости". Чтобы избежать этого, убедитесь, что ваши методы @Bean имеют уникальные имена и корректно описаны.


Практика: настройка реального проекта

Давайте сделаем шаг в сторону нашего учебного приложения. Мы будем создавать сервис для управления книгами в библиотеке, с использованием конфигурационного класса.

Бизнес-логика


public class Book {
    private String title;
    private String author;

    public Book(String title, String author) {
        this.title = title;
        this.author = author;
    }

    @Override
    public String toString() {
        return "Book: " + title + " by " + author;
    }
}

public class LibraryService {
    private Book book;

    public LibraryService(Book book) {
        this.book = book;
    }

    public void displayBookInfo() {
        System.out.println(book.toString());
    }
}

Конфигурационный класс


@Configuration
public class LibraryConfig {

    @Bean
    public Book defaultBook() {
        return new Book("Clean Code", "Robert C. Martin");
    }

    @Bean
    public LibraryService libraryService() {
        return new LibraryService(defaultBook());
    }
}

Использование в основном приложении


import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(LibraryConfig.class);

        LibraryService libraryService = context.getBean(LibraryService.class);
        libraryService.displayBookInfo();
    }
}

Итоговый вывод программы:


Book: Clean Code by Robert C. Martin

Поздравляю! Мы рассмотрели, как использовать конфигурационные классы и создавать Spring Beans. Теперь вы можете конструировать объекты, связывать их зависимости и заставлять IoC-контейнер работать на вас.

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