Какой scope бина Spring создаётся для нового HTTP-запроса?

Ответ

Для каждого нового HTTP-запроса в Spring MVC создаётся отдельный экземпляр бина с областью видимости request.

Принцип работы:

  • В начале обработки каждого HTTP-запроса Spring создаёт новый экземпляр такого бина.
  • Все внедрения (@Autowired) в рамках обработки одного запроса ссылаются на один и тот же объект.
  • После завершения обработки запроса и отправки ответа бин уничтожается сборщиком мусора.

Пример объявления:

@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestScopedBean {
    private String requestId = UUID.randomUUID().toString();
    // Уникален для каждого запроса
}

Ключевые моменты:

  1. Аннотация: Используется @Scope("request") или @RequestScope (начиная с Spring 4.3).
  2. Проксирование (proxyMode): Обязательно для инъекции в бины с более длительным scope (например, singleton). Прокси откладывает получение реального экземпляра до момента вызова метода.
  3. Использование: Идеально для хранения данных, специфичных для запроса: аутентификации пользователя, параметров транзакции, временных вычислений.

Ответ 18+ 🔞

А, ну это же классика, блядь! Вечная тема, про которую каждый второй джуниор на собеседовании обосрётся, как Герасим Муму в озеро.

Смотри, суть проще пареной репы, если без этих твоих заумных слов. Представь себе столовую, ёпта.

Каждый новый голодный мудак, который приходит и орёт «Мне борща!» — это новый HTTP-запрос. И для этого конкретного распиздяя повар (то есть Spring) накрывает отдельный, новый, чистый поднос. Это и есть твой бин с областью request.

Как это работает, если по-человечески:

  • Пришёл Вася — ему выкатили новый поднос. Положили ложку, вилку, хлебушек. Это его личный RequestScopedBean.
  • Пока Васю кормят (обрабатывают его запрос), все повара на кухне (@Autowired-зависимости) кладут еду именно на этот васин поднос.
  • Вася поел, обосрался довольный и ушёл. Поднос — нахуй в мойку. Объект уничтожается. Память свободна. Всё чисто.

Вот как это объявляется, смотри на код, не отвлекайся:

@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestScopedBean {
    private String requestId = UUID.randomUUID().toString();
    // Этот ID будет уникальным для каждого нового подноса-запроса, ёпта!
}

А теперь главные подводные ебучки, о которые все бьются:

  1. Аннотация: Можно писать @Scope("request"). А можно, если ты не лох и у тебя Spring 4.3+, просто @RequestScope. Красиво и понятно, как Муму в мешке.

  2. Проксирование (proxyMode): Вот это, блядь, самый сок! Без этого — пиздец и NullPointerException. Смотри, зачем это: у тебя есть главный шеф-повар (singleton-бин), который живёт один на всю столовую. И ты хочешь ему всучить поднос (request-бин) для Васи. Но шеф создаётся один раз при старте, а Вася со своим подносом появится только когда придёт!

    Вот тут и нужен прокси — хуй в пальто, обманка. Spring подсовывает шефу не реальный поднос, а его заглушку-куклу. И когда шефу реально понадобится что-то положить на поднос (вызвать метод), эта кукла-прокси скажет: «Ага, ща, погоди!», побежит, найдёт уже созданный для текущего Васи поднос и даст шефу работать с ним. Магия, блядь! ScopedProxyMode.TARGET_CLASS — это и есть инструкция «сделай такую обманку».

  3. Где это применять? Да везде, где данные живут ровно один запрос! Данные авторизации пользователя, его корзина покупок на время сессии (хотя для сессии есть session scope), какие-то временные вычисления, которые потом нахуй не нужны. В общем, всё, что должно умереть сразу после ответа «ОК, Вася, иди нахуй».

Короче, запомни: request scope — это одноразовый поднос для каждого нового голодраного клиента. Съел — выкинул. И не забудь про прокси, а то останешься с голой жопой и ошибкой в логах.