MVC
Model–View–Controller разделяет представление, обработку пользовательского ввода и данные/состояние экрана.
- Model — данные, которые нужны представлению; не обязательно JPA-сущность;
- View — превращает model в HTML или другое представление;
- Controller — принимает ввод, вызывает прикладной слой и выбирает ответ.
В REST-приложении Spring MVC controller чаще возвращает DTO, а HttpMessageConverter сериализует его в JSON. Это всё ещё request-response модель Spring MVC, хотя серверная HTML-view не используется.
DispatcherServlet
DispatcherServlet — front controller Spring MVC. Типичный путь запроса:
flowchart LR A["HTTP request"] --> B["Filter chain"] B --> C["DispatcherServlet"] C --> D["HandlerMapping"] D --> E["HandlerAdapter"] E --> F["Controller"] F --> G["Application service"] F --> H["ViewResolver or MessageConverter"] H --> I["HTTP response"]
- Servlet-фильтры обрабатывают запрос до Spring MVC.
HandlerMappingнаходит handler по path, method и другим условиям.HandlerAdapterвызывает подходящий controller-метод.- Argument resolvers собирают параметры, DTO и служебные объекты.
- Controller вызывает use case.
- Результат преобразуется view renderer или message converter.
- Исключение может обработать
HandlerExceptionResolver/@ControllerAdvice.
Пример REST-controller
@RestController
@RequestMapping("/orders")
class OrderController {
private final OrderQueryService orders;
OrderController(OrderQueryService orders) {
this.orders = orders;
}
@GetMapping("/{id}")
OrderResponse get(@PathVariable long id) {
return orders.get(id);
}
@PostMapping
ResponseEntity<OrderResponse> create(
@Valid @RequestBody CreateOrderRequest request) {
OrderResponse created = orders.create(request);
return ResponseEntity
.created(URI.create("/orders/" + created.id()))
.body(created);
}
}Controller координирует HTTP-детали, но не содержит транзакционный алгоритм и прямую работу с EntityManager.
DTO и сущности
Возврат JPA-сущности наружу создаёт проблемы:
- lazy-загрузка во время сериализации;
- циклические связи;
- случайная публикация внутренних полей;
- API становится связан со схемой хранения.
DTO фиксирует внешний контракт и позволяет валидировать вход независимо от domain model.
Filter, Interceptor, AOP
- servlet
Filterвидит сырой request/response и работает до DispatcherServlet; HandlerInterceptorзнает выбранный MVC handler;@ControllerAdviceцентрализует обработку MVC-ошибок;- AOP перехватывает вызовы Spring-бинов и не является HTTP-механизмом.
Выбор зависит от уровня данных, который нужен задаче.
Потоки
Singleton-controller обслуживает запросы из разных потоков. В нём нельзя хранить изменяемое состояние конкретного запроса в полях. Локальные переменные и immutable dependencies безопаснее.
В обычном Spring MVC один request обычно занимает servlet-thread до формирования ответа. Async MVC освобождает контейнерный поток на части ожидания, но отличается от полной reactive-модели WebFlux.
На собеседовании
Кто вызывает controller? DispatcherServlet через выбранные HandlerMapping и HandlerAdapter.
@Controller и @RestController? @RestController включает семантику @ResponseBody: возвращаемое значение записывается в response через converter, а не трактуется как имя view.
Связанные заметки: Контроллеры Spring, Spring WEB, Http протокол, Фильтры Filters слушатели Listeners и перехватчики Interceptors.