JavaRush /Курси /Модуль 5. Spring /Скоупи бінів (singleton, prototype тощо)

Скоупи бінів (singleton, prototype тощо)

Модуль 5. Spring
Рівень 2 , Лекція 5
Відкрита

Скоуп (Scope) у Spring — це правило, яке визначає життєвий цикл біна: коли створювати новий екземпляр об'єкта, як довго його зберігати і коли знищувати. Це схоже на правила керування ресурсами — деякі ресурси треба створювати один раз і повторно використовувати, а інші вимагають нового екземпляра при кожному зверненні.

Скоупи важливі, бо в різних частинах вашого додатку можуть бути різні вимоги до створення об'єктів. Наприклад:

  • Для сервісів "без стану" (stateless) ми хочемо використовувати той самий екземпляр у всьому додатку.
  • А для об'єктів, що зберігають унікальні дані для кожного HTTP-запиту, нам потрібен новий екземпляр для кожного запиту.

У реальному проєкті розуміння скоупів допомагає гнучко керувати ресурсами і покращувати продуктивність додатку.


Стандартні скоупи Spring

Давайте розглянемо основні скоупи Spring:

  1. Singleton (за замовчуванням)
  2. Prototype
  3. Request
  4. Session
  5. Application

Singleton: "Один для всіх"

Singleton — це скоуп за замовчуванням. Коли бін позначений цим скоупом (або взагалі не позначений), Spring створює тільки один екземпляр біна для всього ApplicationContext. Цей бін буде використовуватися повторно щоразу, коли його запитують.


@Component
public class SingletonExample {
    public SingletonExample() {
        System.out.println("Singleton бін створено");
    }
}

Якщо ви додасте згаданий вище бін у дві різні частини додатку, наприклад, у два різні класи, Spring створить один екземпляр і буде передавати його скрізь. Ось приклад:


@Component
public class MyService {

    private final SingletonExample singletonExample;

    @Autowired
    public MyService(SingletonExample singletonExample) {
        this.singletonExample = singletonExample;
        System.out.println("MyService отримав бін SingletonExample");
    }
}

@Component
public class AnotherService {

    private final SingletonExample singletonExample;

    @Autowired
    public AnotherService(SingletonExample singletonExample) {
        this.singletonExample = singletonExample;
        System.out.println("AnotherService отримав бін SingletonExample");
    }
}

Результат:


Singleton бін створено
MyService отримав бін SingletonExample
AnotherService отримав бін SingletonExample

Prototype: "На кожен запит — новий бін"

Prototype — скоуп для випадків, коли вам потрібен новий екземпляр біна при кожному запиті. Це корисно, якщо бін містить стан, який змінюється в залежності від бізнес-логіки.


@Component
@Scope("prototype")
public class PrototypeExample {
    public PrototypeExample() {
        System.out.println("Prototype бін створено");
    }
}

Якщо два різні компоненти запросять PrototypeExample, Spring створить два окремі екземпляри.


@Component
public class MyPrototypeService {

    private final PrototypeExample prototypeExample;

    @Autowired
    public MyPrototypeService(PrototypeExample prototypeExample) {
        this.prototypeExample = prototypeExample;
        System.out.println("MyPrototypeService отримав бін PrototypeExample");
    }
}

@Component
public class AnotherPrototypeService {

    private final PrototypeExample prototypeExample;

    @Autowired
    public AnotherPrototypeService(PrototypeExample prototypeExample) {
        this.prototypeExample = prototypeExample;
        System.out.println("AnotherPrototypeService отримав бін PrototypeExample");
    }
}

Результат:


Prototype бін створено
MyPrototypeService отримав бін PrototypeExample
Prototype бін створено
AnotherPrototypeService отримав бін PrototypeExample

Request: "Новий бін для кожного HTTP-запиту"

Цей скоуп використовується у веб-додатках. На кожен новий HTTP-запит створюється окремий екземпляр біна.


@Component
@Scope("request")
public class RequestScopedBean {
    public RequestScopedBean() {
        System.out.println("Request бін створено");
    }
}
⚠️ Увага:

використовувати цей scope можна лише в додатку з підтримкою веб-контексту, наприклад, зі Spring MVC.

Session: "Один бін на сесію користувача"

Session-скоуп створює бін, унікальний для сесії користувача.


@Component
@Scope("session")
public class SessionScopedBean {
    public SessionScopedBean() {
        System.out.println("Session бін створено");
    }
}

Application: "Один бін для всього контексту додатку"

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


Як налаштувати скоупи?

Скоупи можна налаштувати за допомогою анотації @Scope. Ось приклад, як вказати скоуп для бінів:


@Component
@Scope("prototype") // Вказуємо scope для цього біна
public class MyPrototypeBean {
    // Логіка біна
}

Для веб-орієнтованих скоупів (request, session, application) ви можете використовувати аналогічний підхід.

Як правильно вибрати скоуп?

Singleton ідеально підійде для сервісів без стану. Наприклад, сервіс відправки email — він просто виконує дію і не зберігає дані.

Prototype потрібен, коли кожному користувачу потрібен свій екземпляр. Уявіть форму реєстрації — у кожного свої дані.

Request/Session допомагають працювати з веб-даними. Наприклад, кошик в інтернет-магазині живе в межах сесії користувача.

Увага: вибір скоупу впливає на пам'ять і швидкодію. Особливо уважно використовуйте prototype — кожен новий екземпляр займає пам'ять, і її потрібно вчасно звільняти.

Типові помилки при використанні скоупів

  1. Використання prototype-бінів у singleton-бінах: якщо ви додасте prototype-бін у singleton-бін через DI,
  2. Spring створить лише один екземпляр prototype і прикріпить його до singleton. Для виправлення можна використовувати інтерфейс ObjectFactory або анотацію @Lookup.

  3. Спроба використовувати веб-орієнтовані скоупи у НЕ веб-додатку: у цьому випадку ви отримаєте помилку No Scope Registered for ScopeName.


Тепер ви можете впевнено працювати зі скоупами в Spring Framework, використовуючи їх для створення гнучких та масштабованих додатків! У наступній лекції розберемо анотації @Configuration і @Bean, які допоможуть вам ще краще керувати конфігураціями та бін-фабриками.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ