Как долго существует контекст запроса, созданный DispatcherServlet
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Жизненный цикл контекста запроса в DispatcherServlet
Временные рамки существования контекста
Контекст запроса, создаваемый DispatcherServlet в Spring Framework, существует на протяжении всего времени обработки одного HTTP запроса. Его жизненный цикл строго определен и охватывает период от момента, когда запрос поступает в сервлет, до момента, когда ответ полностью сформирован и отправлен клиенту.
Основные этапы жизненного цикла
1. Инициализация контекста (request scope)
Когда DispatcherServlet получает HTTP запрос, на уровне контейнера сервлета (Servlet API) создается объект RequestContext:
// Автоматически создается Spring в начале обработки
public class DispatcherServlet extends FrameworkServlet {
@Override
protected void doDispatch(HttpServletRequest request,
HttpServletResponse response) throws Exception {
// Здесь начинает существовать RequestContext
RequestContextHolder.setRequestAttributes(
new ServletRequestAttributes(request));
try {
// Обработка запроса
} finally {
// Контекст удаляется в finally блоке
RequestContextHolder.resetRequestAttributes();
}
}
}
2. Доступность во время обработки
Контекст доступен во всех компонентах, участвующих в обработке запроса:
- Controllers — имеют полный доступ
- Services — могут получать текущий request через RequestContextHolder
- Repositories — могут использовать request-scoped бины
- Filters и Interceptors — видят и могут модифицировать контекст
@RestController
public class MyController {
@GetMapping("/data")
public ResponseEntity<?> getData() {
// RequestContext доступен здесь
HttpServletRequest request =
((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getRequest();
return ResponseEntity.ok(request.getHeader("X-Custom-Header"));
}
}
3. Завершение и очистка
Контекст удаляется в блоке finally после отправки ответа:
try {
// Весь процесс обработки
doDispatch(request, response);
} finally {
// Очистка RequestContextHolder
RequestContextHolder.resetRequestAttributes();
}
Практические последствия
Request-scoped бины
Бины с областью видимости request создаются один раз за жизненный цикл контекста:
@Configuration
public class RequestScopeConfig {
@Bean
@Scope(value = WebApplicationContext.SCOPE_REQUEST,
proxyMode = ScopedProxyMode.TARGET_CLASS)
public RequestMetadata requestMetadata() {
return new RequestMetadata();
}
}
ThreadLocal хранилище
Spring использует ThreadLocal для хранения RequestContext, что обеспечивает thread-safe доступ:
public abstract class RequestContextHolder {
private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
new NamedThreadLocal<>("Request attributes");
public static RequestAttributes getRequestAttributes() {
RequestAttributes attributes = requestAttributesHolder.get();
if (attributes == null) {
throw new IllegalStateException(
"No thread-bound request found");
}
return attributes;
}
}
Асинхронные запросы (Async/Await)
Для асинхронных операций поведение отличается:
@GetMapping("/async")
public CompletableFuture<String> asyncRequest() {
// Контекст сохраняется для асинхронной операции
return CompletableFuture.supplyAsync(() -> {
// RequestContext может быть недоступен здесь
// без дополнительной настройки
return "result";
});
}
Для асинхронных операций нужно явно сохранять и восстанавливать контекст.
Выводы
- Время жизни: Контекст существует от начала обработки HTTP запроса до отправки полного ответа
- Область видимости: Ограничен одним HTTP запросом и одним потоком (в стандартном Tomcat)
- Автоматическое управление: Spring полностью управляет созданием и удалением контекста
- Thread-safe: Реализовано через ThreadLocal, безопасно в многопоточной среде
- Важно для разработчика: Помнить, что request-scoped компоненты недоступны за пределами обработки запроса