Может ли быть два контроллера с одинаковыми путями в Spring?
Что проверяют
Знаете ли вы, как Spring MVC строит таблицу маршрутов и в какой момент ловит конфликт. Интервьюеру важно услышать, что уникальным должен быть не путь, а весь набор условий маппинга. Следом часто спрашивают, как Spring выбирает обработчик, если под запрос подходят сразу несколько.
Как отвечать
Два контроллера с одним @RequestMapping("/api/users") на уровне класса это нормальная ситуация, если методы внутри различаются. При старте RequestMappingHandlerMapping собирает для каждого метода набор условий, и сравнивается он целиком:
- HTTP-метод:
@GetMappingв одном контроллере и@PostMappingна тот же путь в другом уживаются спокойно; paramsиheaders: например,params = "type=admin"разводит запросы на один и тот же адрес;consumesиproduces: один метод принимает JSON, другойmultipart/form-data;- версия API: в Spring Framework 7 у
@RequestMappingпоявился атрибутversion, и при настроенной стратегии версионирования одинаковые пути разводятся по версии.
Если совпадает всё, приложение просто не поднимется: контекст упадёт с IllegalStateException: Ambiguous mapping и назовёт оба бина. То есть это ошибка старта, а не случайный выбор обработчика в рантайме.
Второй сценарий тоньше. Пути /users/{id} и /users/{name} при регистрации считаются разными, но под запрос /users/42 подходят одинаково. Тогда исключение Ambiguous handler methods вылетит уже на запросе. А вот /users/me и /users/{id} конфликта не дают: Spring сортирует совпадения по специфичности, и литеральный сегмент побеждает переменную.
Где спотыкаются
Говорят, что Spring «выберет первый попавшийся контроллер» или вернёт случайный ответ. Полный дубль ломает запуск, и это легко проверить.
Считают, что конфликт определяется только строкой пути, и забывают про метод, заголовки и типы контента. Из-за этого не могут объяснить, почему GET и POST на один адрес живут в разных классах.
Разводят маршруты через params или заголовки там, где нужен отдельный путь. Такой API трудно описать в OpenAPI и легко сломать клиенту, который забыл параметр.