Урок 09 из 18 · 2 минуты чтения

Сервлеты, фильтры и встроенный контейнер

Сервлет и встроенный Tomcat, модель thread-per-request, потокобезопасность контроллеров, Filter против Interceptor и forward/redirect.

Сервлет и встроенный контейнер

Сервлет-контейнер управляет жизненным циклом сервлета: init() при загрузке, service() (→ doGet/doPost) на каждый запрос, destroy() при выгрузке. В Spring MVC единственный центральный сервлет — DispatcherServlet, через него проходят все запросы.

Ключевой сдвиг Spring Boot: контейнер встроен (по умолчанию Tomcat; альтернативы — Jetty, Undertow). Приложение собирается в самодостаточный исполняемый jar со встроенным сервером, а не разворачивается WAR-файлом на внешний сервер приложений — это упрощает деплой и контейнеризацию.

Модель thread-per-request

Контейнер держит пул рабочих потоков (у Tomcat по умолчанию ~200). Каждый входящий запрос берёт один поток из пула и держит его всё время обработки, включая блокирующие ожидания (БД, внешние вызовы).

Отсюда потолок: при блокирующем IO число одновременных запросов ограничено размером пула — потоки простаивают в ожидании. Это и есть мотивация WebFlux (неблокирующая модель) и виртуальных потоков (дешёвые потоки), которым посвящены отдельные уроки.

Потокобезопасность контроллеров

Один экземпляр сервлета (и singleton-контроллера Spring) обслуживает множество запросов параллельно разными потоками. Поэтому состояние конкретного запроса НЕЛЬЗЯ хранить в полях контроллера/сервлета — это гонка данных.

Правило: в полях держат только потокобезопасные зависимости (другие бины), а данные запроса живут в параметрах метода, локальных переменных или request-scope бинах. Мутабельное поле-«состояние» в singleton-контроллере — классический баг.

Filter против Interceptor

Servlet Filter работает на уровне контейнера ДО DispatcherServlet и оборачивает всю обработку: CORS, security, сжатие, логирование, correlation id. Фильтры образуют цепочку (FilterChain), а порядок задают через @Order или FilterRegistrationBean.

HandlerInterceptor работает ВНУТРИ MVC, вокруг выбранного обработчика: preHandle/postHandle/afterCompletion, с доступом к тому, какой handler выбран. Выбор: нужна низкоуровневая обработка любого запроса и доступ к сырым servlet API — Filter; нужна логика, привязанная к MVC-обработчику — Interceptor.

forward и redirect

forward — серверная передача обработки другому ресурсу в рамках ТОГО ЖЕ запроса: новый запрос браузера не делается, URL не меняется. redirect — ответ 3xx, после которого клиент делает НОВЫЙ запрос на другой URL (URL в адресной строке меняется).

Отсюда паттерн PRG (Post/Redirect/Get): после успешного POST отвечают редиректом на GET-страницу, чтобы перезагрузка (F5) не повторяла отправку формы/платежа.

Как отвечать на собеседовании

Объясните встроенный контейнер (jar вместо WAR) и модель thread-per-request (поток из пула на запрос, блокировка на IO → мотивация WebFlux/виртуальных потоков). Подчеркните потокобезопасность singleton-контроллеров (нет состояния запроса в полях). Различите Filter (до DispatcherServlet, контейнерный, цепочка) и Interceptor (внутри MVC, вокруг handler), и forward vs redirect с паттерном PRG.

Проверка урока

Войдите, чтобы проверить себя: сданные проверки всех уроков курса отмечают его темы пройденными на карте и в ИПР.

Вопросы по теме

Читайте также

Партнёр платформы

Разбор собеседования с sotto

После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.

Разбор собеседования