JavaRush /Курсы /Модуль 5. Spring /Введение в Spring Beans и жизненный цикл бина

Введение в Spring Beans и жизненный цикл бина

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

1. Повторное знакомство со Spring Beans

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

Представьте себе менеджера на складе, который всегда знает, где лежит нужный вам инструмент (или объект). Вот таким менеджером и является IoC-контейнер, а инструменты на складе — это наши бины.

Как бины регистрируются в Spring?

Есть несколько способов зарегистрировать бины:

  • Аннотации (например, @Component, @Service, @Repository).
  • Java-based конфигурация с использованием @Configuration и @Bean.
  • XML-конфигурация (да, она всё ещё существует, но используется всё реже, ибо зачем, когда есть Java-аннотации?).

Вот почему Spring гибок — выбирайте удобный способ регистрации бинов.


2. Жизненный цикл Spring Bean

Бины, как и все живые организмы, имеют жизненный цикл. Этот жизненный путь включает этапы создания, инициализации, использования и удаления — всё это контролируется IoC-контейнером. Давайте разберёмся, как это работает.

Основные этапы жизненного цикла

  1. Создание: бин создаётся IoC-контейнером.
  2. Инициализация: в этот момент бин может настроить свои внутренние состояния.
  3. Использование: бин начинает выполнять свою работу (например, обрабатывает запросы).
  4. Уничтожение: как только бин больше не нужен, контейнер уничтожает его (если, конечно, это не синглтон).

Визуализация жизненного цикла


1. Создание объекта
          ↓
2. Установка зависимостей (DI)
          ↓
3. Вызов методов инициализации (@PostConstruct)
          ↓
4. Использование бина
          ↓
5. Очистка ресурсов (@PreDestroy)

Теперь давайте разберём конкретный пример.


3. Как Spring управляет жизненным циклом?

Для этого у Spring есть удобные аннотации. Давайте познакомимся с ключевыми из них.

Аннотации @PostConstruct и @PreDestroy

  • @PostConstruct: выполняет действия после создания бина и установки всех его зависимостей (например, подключает сервис или загружает данные).
  • @PreDestroy: срабатывает перед уничтожением бина. Используется для освобождения ресурсов (например, закрытия соединений).

Пример:


import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Component
public class LifecycleDemoBean {

    @PostConstruct
    public void init() {
        System.out.println("Бин инициализирован!");
    }

    public void doSomething() {
        System.out.println("Бин работает!");
    }

    @PreDestroy
    public void cleanup() {
        System.out.println("Бин уничтожен!");
    }
}

Когда Spring видит аннотации @PostConstruct и @PreDestroy, он гарантирует, что эти методы будут вызваны в соответствующие моменты.


Альтернатива с интерфейсами InitializingBean и DisposableBean

Если вы предпочитаете интерфейсы вместо аннотаций (например, для более явного контракта), можно использовать:

  • InitializingBean — метод afterPropertiesSet() вызывается после создания бина.
  • DisposableBean — метод destroy() вызывается перед уничтожением бина.

Пример:


import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

@Component
public class AlternativeLifecycleBean implements InitializingBean, DisposableBean {

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Объект настроен (InitializingBean)!");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("Объект уничтожен (DisposableBean)!");
    }
}

Хотя такой подход работает, в современных проектах чаще используют аннотации @PostConstruct и @PreDestroy за их простоту и читаемость.


4. Управление бинами с помощью аннотаций

@Component и компания**

  • @Component: общая аннотация для любого бина, которую применяют, если специализированная аннотация не подходит.
  • @Service: для классов с бизнес-логикой.
  • @Repository: для классов, отвечающих за доступ к данным.
  • @Controller: для MVC-контроллеров.

Пример использования @Component:


@Component
public class SimpleBean {
    public void sayHello() {
        System.out.println("Привет, мир бинов!");
    }
}

@Autowired и автоматическое внедрение зависимостей

Мы уже немного говорили о внедрении зависимостей, но давайте углубимся.

  • @Autowired: позволяет Spring автоматически настроить зависимости.

Пример работы с @Autowired:


@Component
public class DependencyBean {
    public String getDependencyInfo() {
        return "Информация о зависимости.";
    }
}

@Component
public class AutowiredBean {

    private final DependencyBean dependency;

    @Autowired
    public AutowiredBean(DependencyBean dependency) {
        this.dependency = dependency;
    }

    public void printDependencyInfo() {
        System.out.println(dependency.getDependencyInfo());
    }
}

При запуске Spring сам найдёт DependencyBean и передаст его в AutowiredBean.


5. Скоупы бинов

По умолчанию все бины в Spring имеют скоуп singleton. Это значит, что существует только один экземпляр бина в IoC-контейнере. Но иногда нам нужно управлять скоупами.

Основные скоупы

  • Singleton: один бин на весь IoC-контейнер.
  • Prototype: новый объект создаётся каждый раз, когда бин запрашивается.
  • Request: один экземпляр для каждого HTTP-запроса.
  • Session: один экземпляр для каждой HTTP-сессии.

Установка скоупа

Аннотация @Scope позволяет управлять жизненным циклом бина.


import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype")
public class PrototypeBean {
    public PrototypeBean() {
        System.out.println("Создан новый экземпляр PrototypeBean!");
    }
}

При каждом использовании этого бина создаётся новый экземпляр.


6. Типичные ошибки и их устранение

  1. Ошибка с отсутствием зависимости: если вы используете @Autowired, но бин не зарегистрирован, Spring бросит исключение NoSuchBeanDefinitionException. Решение? Убедитесь, что бин зарегистрирован через аннотацию или конфигурацию.
  2. Уничтожение бина-прототипа: Spring не управляет жизненным циклом prototype-бинов, поэтому уничтожайте их сами.
  3. Множественное совпадение бинов: если у вас несколько бинов одного типа, Spring может запутаться. Используйте @Qualifier для указания конкретного бина.

Пример @Qualifier:


@Component("catBean")
public class Cat {}

@Component("dogBean")
public class Dog {}

@Component
public class AnimalShelter {

    @Autowired
    @Qualifier("catBean") // Указываем, какой бин использовать
    private Cat pet;
}

Откуда мы это всё знаем?

Если хотите копать глубже, вот пара полезных ссылок:


Да здравствуют бины, жизненный цикл и упрощение нашей жизни! Следующий шаг — ещё больше магии Spring!

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