← Назад к вопросам
Как Spring MVC взаимодействует с сервлетами
2.0 Middle🔥 181 комментариев
#Spring Framework
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как Spring MVC взаимодействует с сервлетами
Основная идея
Spring MVC построена НА БАЗЕ сервлетов, но скрывает их сложность. Вместо создания многих сервлетов, Spring MVC использует один фронт-контроллер сервлета (DispatcherServlet), который маршрутизирует все HTTP запросы нужным обработчикам.
Сервлет: фундамент
Забыли, что такое сервлет?
// Сервлет — это Java класс, который обрабатывает HTTP запросы
public class GreetingServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
// 1. Получаю параметр из URL: /greeting?name=John
String name = req.getParameter("name");
// 2. Формирую ответ
resp.setContentType("text/html");
resp.getWriter().println("<h1>Hello, " + name + "!</h1>");
}
}
Без Spring MVC: много сервлетов
Требование: обработать разные URL:
- GET /users → получить всех пользователей
- GET /users/{id} → получить одного пользователя
- POST /users → создать пользователя
- PUT /users/{id} → обновить
- DELETE /users/{id} → удалить
Решение БЕЗ Spring:
Нужно создать МНОГО сервлетов и зарегистрировать каждый в web.xml
<!-- web.xml — адское настраивание -->
<web-app>
<servlet>
<servlet-name>GetUsersServlet</servlet-name>
<servlet-class>com.example.GetUsersServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>GetUsersServlet</servlet-name>
<url-pattern>/users</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>GetUserByIdServlet</servlet-name>
<servlet-class>com.example.GetUserByIdServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>GetUserByIdServlet</servlet-name>
<url-pattern>/users/{id}</url-pattern>
</servlet-mapping>
<!-- ... и так для каждого эндпоинта ... -->
</web-app>
// GetUsersServlet.java
public class GetUsersServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
// Получу всех пользователей и отправлю JSON
}
}
// GetUserByIdServlet.java
public class GetUserByIdServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
String id = req.getPathInfo(); // /users/123
// Получу пользователя с ID=123
}
}
// ... дублирование кода для каждого эндпоинта!
С Spring MVC: фронт-контроллер
Вместо:
/users → GetUsersServlet
/users/{id} → GetUserByIdServlet
/posts → GetPostsServlet
Spring делает:
ВСЕ запросы → DispatcherServlet (один сервлет!) → маршрутизирует контроллерам
Теперь просто:
// Один контроллер обрабатывает ВСЕ эндпоинты
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping // GET /api/users
public List<User> getAllUsers() {
return userService.findAll();
}
@GetMapping("/{id}") // GET /api/users/123
public User getUserById(@PathVariable Long id) {
return userService.findById(id);
}
@PostMapping // POST /api/users
public User createUser(@RequestBody User user) {
return userService.save(user);
}
@PutMapping("/{id}") // PUT /api/users/123
public User updateUser(@PathVariable Long id, @RequestBody User user) {
return userService.update(id, user);
}
@DeleteMapping("/{id}") // DELETE /api/users/123
public void deleteUser(@PathVariable Long id) {
userService.delete(id);
}
}
Всё! Никаких web.xml, никаких отдельных сервлетов.
Архитектура: как Spring MVC работает с сервлетами
1. HTTP запрос идёт в DispatcherServlet (фронт-контроллер)
2. DispatcherServlet определяет, какой контроллер обработает запрос
3. Контроллер обрабатывает запрос
4. Spring преобразует результат в HTTP ответ
5. Ответ идёт клиенту
Визуально:
HTTP запрос (GET /api/users/123)
|
v
DispatcherServlet (extends HttpServlet)
|
+-- Определяет маршрут /api/users/{id}
|
+-- Находит UserController.getUserById()
|
v
HandlerMapping (/api/users/{id} -> UserController#getUserById)
|
v
UserController.getUserById(123) // Бизнес-логика
|
v
return User(123, "John", ...)
|
v
ViewResolver / MessageConverter (объект -> JSON)
|
v
HTTP 200 OK с JSON: {"id": 123, "name": "John", ...}
web.xml настройка DispatcherServlet
<web-app>
<!-- DispatcherServlet — основной сервлет Spring MVC -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- Spring контекст конфиг -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-servlet.xml</param-value>
</init-param>
<!-- Загружать при старте приложения -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Все запросы идут в DispatcherServlet -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Сейчас (Spring Boot):
// Никаких XML!
// Spring Boot автоматически регистрирует DispatcherServlet
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
// Конфиг через application.properties:
server.servlet.context-path=/api
Компоненты Spring MVC
public class RequestProcessingFlow {
/*
1. DispatcherServlet (extends HttpServlet)
└─ Фронт-контроллер, получает все запросы
2. HandlerMapping
└─ Определяет, какой контроллер обработает запрос
└─ Примеры: @RequestMapping, путь /api/users/{id}
3. HandlerAdapter
└─ Адаптер для вызова метода контроллера
└─ Обрабатывает аннотации (@PathVariable, @RequestBody и т.д.)
4. Controller (ваш код)
└─ Бизнес-логика
└─ Возвращает модель (Model) или значение (@ResponseBody)
5. ViewResolver
└─ Преобразует имя представления в View (только для HTML)
└─ Пример: "userList" -> /WEB-INF/views/userList.jsp
6. View (опционально)
└─ JSP, Thymeleaf, FreeMarker — отрисовывает HTML
└─ Для REST API не нужно (используются MessageConverters)
7. MessageConverter
└─ Преобразует объект в JSON/XML (для REST)
└─ Пример: User -> {"id": 123, "name": "John"}
*/
}
Пример: запрос обрабатывается пошагово
Запрос: POST /api/users с JSON телом {"name": "John", "email": "john@example.com"}
1. DispatcherServlet.service(request, response)
└─ Фронт-контроллер ловит запрос
2. HandlerMapping.getHandler(request)
└─ Ищет контроллер для /api/users
└─ Находит: UserController.createUser()
3. HandlerAdapter.handle(handler, request, response)
└─ Адаптер вызывает контроллер
└─ Парсит параметры, аннотации (@RequestBody, @PathVariable и т.д.)
└─ Преобразует JSON -> User объект
4. UserController.createUser(@RequestBody User user)
└─ Ваша логика
└─ userService.save(user);
└─ return new User(1, "John", "john@example.com");
5. MessageConverter.write(user, response)
└─ Jackson преобразует User -> JSON
└─ JSON отправляется клиенту
Ответ: HTTP 200 OK с телом {"id": 1, "name": "John", "email": "john@example.com"}
Интернальное устройство DispatcherServlet
public class DispatcherServlet extends FrameworkServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) {
// Это вызывается для КАЖДОГО HTTP запроса
// 1. Определяю маршрут
HandlerExecutionChain chain = getHandler(request);
// chain содержит: контроллер + интерцепторы
// 2. Вызываю интерцепторы (до обработки)
for (HandlerInterceptor interceptor : chain.getInterceptors()) {
interceptor.preHandle(request, response);
}
// 3. Получаю адаптер контроллера
HandlerAdapter adapter = getHandlerAdapter(chain.getHandler());
// 4. Вызываю контроллер
ModelAndView mav = adapter.handle(request, response, chain.getHandler());
// 5. Интерцепторы (после обработки)
for (HandlerInterceptor interceptor : chain.getInterceptors()) {
interceptor.postHandle(request, response, mav);
}
// 6. Отрисовка (ViewResolver) или преобразование в JSON (MessageConverter)
render(mav, request, response);
}
}
Сравнение: сервлет vs Spring MVC
┌─────────────────────┬──────────────────────┬──────────────────────┐
│ Аспект │ Чистый Сервлет │ Spring MVC │
├─────────────────────┼──────────────────────┼──────────────────────┤
│ Количество классов │ По одному на URL │ Один DispatcherServlet|
│ Маршрутизация │ Вручную в web.xml │ @RequestMapping │
│ Парсинг параметров │ req.getParameter() │ @PathVariable, │
│ │ вручную │ @RequestBody │
│ Преобразование JSON │ Вручную GSON/Jackson │ Автоматически │
│ Код │ Многословный │ Лаконичный │
│ Масштабируемость │ Сложно добавлять URL │ Просто добавить метод │
└─────────────────────┴──────────────────────┴──────────────────────┘
Итого
Spring MVC — это фреймворк, построенный НА ОСНОВЕ сервлетов. Он использует:
- DispatcherServlet — один основной сервлет, который получает все запросы
- HandlerMapping — определяет, какой контроллер обработать запрос
- HandlerAdapter — вызывает контроллер с правильными параметрами
- MessageConverter — преобразует объекты в JSON
Вместо создания множества сервлетов вручную, вы просто пишете контроллеры с методами, аннотированными @RequestMapping, и Spring всё остальное делает сам.