Как DispatcherServlet в Spring MVC находит контроллеры, помеченные аннотацией @Controller?

«Как DispatcherServlet в Spring MVC находит контроллеры, помеченные аннотацией @Controller?» — вопрос из категории Spring, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

DispatcherServlet находит контроллеры через механизм сканирования компонентов Spring (component scanning), который активируется соответствующей конфигурацией.

Необходимые условия:

  1. Конфигурация сканирования пакетов:

    • Java Config: Использование аннотации @ComponentScan в классе конфигурации.
      @Configuration
      @ComponentScan("com.example.controllers") // Указывает пакет для сканирования
      @EnableWebMvc // Включает поддержку аннотаций MVC
      public class WebConfig implements WebMvcConfigurer {
      // ...
      }
    • XML Config: Использование элемента <context:component-scan> в контексте Spring.
      <context:component-scan base-package="com.example.controllers"/>
      <mvc:annotation-driven/>
  2. Наличие аннотации @Controller (или @RestController): Класс должен быть помечен этой стереотипной аннотацией, которая является специализацией @Component.

    @Controller // Будет обнаружен при сканировании пакета "com.example.controllers"
    public class UserController {
        // ...
    }
  3. Регистрация методов обработчиков: Методы в контроллере должны быть помечены аннотациями маппинга запросов (@GetMapping, @PostMapping, @RequestMapping и т.д.).

Процесс:

  1. При старте приложения Spring сканирует указанные пакеты.
  2. Классы с @Controller регистрируются как бины в ApplicationContext.
  3. DispatcherServlet получает доступ к этому контексту.
  4. Внутренний компонент HandlerMapping (по умолчанию RequestMappingHandlerMapping) индексирует все методы с аннотациями маппинга, связывая URL-шаблоны с конкретными методами контроллеров.
  5. Когда приходит HTTP-запрос, DispatcherServlet запрашивает у HandlerMapping подходящий обработчик (контроллер + метод) и вызывает его.

Если сканирование не настроено или контроллер находится вне сканируемых пакетов, DispatcherServlet его не обнаружит.