Вопрос с собеседования · Spring

Разработчик добавил в @RestController поле private User currentUser и заполняет его в начале каждого метода. Что не так?

MiddleСервлеты и фильтрыSpring
Ещё спрашивают так:
  • Можно ли хранить данные запроса в поле контроллера?
Коротко

Контроллер — singleton, запросы обслуживаются параллельно в разных потоках. Поле currentUser общее: один пользователь увидит данные другого — гонка и утечка.

  • Данные запроса — в локальных переменных и параметрах метода
  • Текущий пользователь — @AuthenticationPrincipal или SecurityContextHolder
  • Request scope — если очень нужно состояние на запрос

А ещё Ошибка не ловится тестами в одном потоке — проявляется под нагрузкой

Подробно

Каждый запрос обрабатывается своим потоком, но экземпляр контроллера один на всех, поэтому запись в поле из одного запроса видна другому — получается гонка, которая на нагрузке проявляется как чужие данные в ответе. Такие баги крайне неприятны: на разработке с одним пользователем всё работает. Правильные способы передать данные запроса — параметры метода, ThreadLocal-подобные механизмы вроде SecurityContextHolder, либо бин со scope request. Общее правило: бины Spring по умолчанию синглтоны, и изменяемое состояние в их полях недопустимо, если оно относится к конкретному запросу.

Что хотят услышать

  • Singleton и параллельные запросы.
  • Почему это гонка и утечка.
  • Правильные способы.

Частые ошибки

  • Хранить в поле сервиса или контроллера что-либо, относящееся к текущему запросу.
  • Считать проблему теоретической — она не воспроизводится при одном пользователе.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✗Ничего: Spring создаёт новый экземпляр контроллера на каждый входящий HTTP-запрос
  • ✗Поле нужно пометить @Autowired
  • ✗Проблема появится только при включённом WebFlux
  • ✓Контроллер — singleton: поле общее для параллельных запросов, данные перемешаются

Что спросят дальше

  • Как устроен SecurityContextHolder и почему он работает?
  • Чем request-scope бин отличается от параметра метода?

Разбор темы

Связанные вопросы

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

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

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

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