← Назад к вопросам

Что такое HandlerAdapters?

2.0 Middle🔥 111 комментариев
#Spring Framework

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое HandlerAdapter (в Spring MVC)

Определение

HandlerAdapter — это компонент Spring MVC, который адаптирует различные типы handlers (обработчиков) к единому интерфейсу, который может использовать DispatcherServlet. Он позволяет Spring работать с разными типами контроллеров.

Проблема, которую решает HandlerAdapter

Если бы HandlerAdapter не существовал, DispatcherServlet должен был бы знать о всех возможных типах handlers:

Без HandlerAdapter:
┌──────────────────────────────────────────┐
│ DispatcherServlet                        │
├──────────────────────────────────────────┤
│ if (handler instanceof Controller)       │
│   → вызови execute()                     │
│ else if (handler instanceof HttpServlet) │
│   → вызови service()                     │
│ else if (handler instanceof Function)    │
│   → вызови apply()                       │
│ else if (handler instanceof ...)         │
│   → ???                                  │
└──────────────────────────────────────────┘
  Код усложняется, нарушается Open/Closed Principle!

С HandlerAdapter:

С HandlerAdapter (паттерн Adapter):
┌──────────────────────────────────────────┐
│ DispatcherServlet                        │
├──────────────────────────────────────────┤
│ adapter = handlerAdapterRegistry         │
│           .getAdapter(handler)           │
│ adapter.handle(request, response)        │
└──────────────────────────────────────────┘
         ↓
    Один унифицированный интерфейс!

Иерархия HandlerAdapter в Spring

public interface HandlerAdapter {
    
    // Проверяет, может ли этот адаптер обработать handler
    boolean supports(Object handler);
    
    // Выполняет handler и возвращает ModelAndView
    ModelAndView handle(
        HttpServletRequest request,
        HttpServletResponse response,
        Object handler
    ) throws Exception;
    
    long getLastModified(HttpServletRequest request, Object handler);
}

Типы HandlerAdapter в Spring

1. SimpleControllerHandlerAdapter — для старых Controller интерфейсов

// Старый стиль (pre-annotation, редко используется)
public class LegacyController implements Controller {
    @Override
    public ModelAndView handleRequest(
            HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        return new ModelAndView("myView");
    }
}

// SimpleControllerHandlerAdapter отвечает за обработку таких контроллеров
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
    @Override
    public boolean supports(Object handler) {
        return (handler instanceof Controller);  // Проверяем тип
    }
    
    @Override
    public ModelAndView handle(
            HttpServletRequest request,
            HttpServletResponse response,
            Object handler) throws Exception {
        
        Controller controller = (Controller) handler;
        return controller.handleRequest(request, response);
    }
}

2. RequestMappingHandlerAdapter — для @RequestMapping (основной)

// Современный стиль (используется по умолчанию)
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        return new User(id, "John");
    }
    
    @PostMapping
    public User createUser(@RequestBody User user) {
        return user;
    }
}

// RequestMappingHandlerAdapter обрабатывает эти контроллеры
// Он:
// 1. Парсит @PathVariable, @RequestParam, @RequestBody
// 2. Вызывает метод с правильными аргументами
// 3. Сериализует результат в JSON/XML
public class RequestMappingHandlerAdapter implements HandlerAdapter {
    @Override
    public boolean supports(Object handler) {
        return (handler instanceof HandlerMethod);
    }
    
    @Override
    public ModelAndView handle(
            HttpServletRequest request,
            HttpServletResponse response,
            Object handler) throws Exception {
        
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        
        // Парсим аргументы
        Object[] args = extractMethodArguments(request, handlerMethod);
        
        // Вызываем метод
        Object returnValue = handlerMethod.getMethod()
            .invoke(handlerMethod.getBean(), args);
        
        // Сериализуем результат
        return handleReturnValue(returnValue, response);
    }
}

3. HttpRequestHandlerAdapter — для HttpRequestHandler

// Для компонентов, реализующих HttpRequestHandler
public class FileDownloadHandler implements HttpRequestHandler {
    @Override
    public void handleRequest(
            HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        
        response.setContentType("application/pdf");
        // Скачиваем файл напрямую
    }
}

// HttpRequestHandlerAdapter
public class HttpRequestHandlerAdapter implements HandlerAdapter {
    @Override
    public boolean supports(Object handler) {
        return (handler instanceof HttpRequestHandler);
    }
    
    @Override
    public ModelAndView handle(
            HttpServletRequest request,
            HttpServletResponse response,
            Object handler) throws Exception {
        
        HttpRequestHandler httpHandler = (HttpRequestHandler) handler;
        httpHandler.handleRequest(request, response);
        return null;  // Нет view, только ответ
    }
}

Как работает HandlerAdapter

1. HTTP Request приходит
   ↓
2. DispatcherServlet получает request
   ↓
3. HandlerMapping находит handler (метод контроллера)
   ↓
4. DispatcherServlet ищет подходящий HandlerAdapter
   ↓
5. HandlerAdapter.supports(handler) → true
   ↓
6. HandlerAdapter.handle() выполняет handler
   ↓
7. Возвращается ModelAndView
   ↓
8. DispatcherServlet отправляет ответ клиенту

Практический пример

import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.ModelAndView;

// Кастомный тип handler
interface CustomHandler {
    String execute();
}

// Реализация
public class MyCustomHandler implements CustomHandler {
    @Override
    public String execute() {
        return "Hello from custom handler";
    }
}

// Кастомный HandlerAdapter
public class CustomHandlerAdapter implements HandlerAdapter {
    
    @Override
    public boolean supports(Object handler) {
        return handler instanceof CustomHandler;
    }
    
    @Override
    public ModelAndView handle(
            HttpServletRequest request,
            HttpServletResponse response,
            Object handler) throws Exception {
        
        CustomHandler customHandler = (CustomHandler) handler;
        String result = customHandler.execute();
        
        // Пишем результат напрямую в response
        response.getWriter().write(result);
        
        return null;  // Нет view
    }
    
    @Override
    public long getLastModified(HttpServletRequest request, Object handler) {
        return -1;
    }
}

// Конфигурация
@Configuration
public class DispatcherServletConfig {
    
    @Bean
    public CustomHandlerAdapter customHandlerAdapter() {
        return new CustomHandlerAdapter();
    }
}

Реальный пример: RequestMappingHandlerAdapter работает так

// При этом запросе:
// GET /api/users/123?sort=name

@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @GetMapping("/{id}")
    public User getUser(
            @PathVariable Long id,           // Из URL
            @RequestParam String sort) {     // Из query параметров
        
        return new User(id, "John", sort);
    }
}

// RequestMappingHandlerAdapter:
// 1. Распознает @PathVariable → парсит из URL
// 2. Распознает @RequestParam → парсит из query
// 3. Вызывает метод с правильными значениями
// 4. Получает User объект
// 5. Сериализует в JSON и отправляет

Цепь HandlerAdapter

Spring пробует адаптеры по порядку:

@Bean
public CompositeHandlerAdapter compositeHandlerAdapter() {
    List<HandlerAdapter> adapters = Arrays.asList(
        new RequestMappingHandlerAdapter(),    // Пробует первым (аннотации)
        new SimpleControllerHandlerAdapter(),  // Потом (старые Controller)
        new HttpRequestHandlerAdapter(),       // Потом (HttpRequestHandler)
        new CustomHandlerAdapter()             // В конце (кастомные)
    );
    
    for (HandlerAdapter adapter : adapters) {
        if (adapter.supports(handler)) {
            return adapter;  // Выбирает первый подходящий
        }
    }
    throw new ServletException("No adapter for handler");
}

Лучшие практики

  1. Используй @RequestMapping вместо старого Controller интерфейса
// ✅ Хорошо
@RestController
public class MyController {
    @GetMapping("/users")
    public List<User> getUsers() { ... }
}

// ❌ Плохо (старый стиль)
public class MyController implements Controller {
    public ModelAndView handleRequest(...) { ... }
}
  1. Кастомные HandlerAdapter для специфичных нужд
// Если нужна нестандартная обработка запросов
public class AuthHandlerAdapter implements HandlerAdapter { ... }

Итоговый вывод

HandlerAdapter — это ключевый компонент Spring MVC, который реализует паттерн Adapter для работы с разными типами handlers. Он позволяет Spring быть гибким и расширяемым, поддерживая как встроенные типы handlers (аннотированные контроллеры, старые Controller интерфейсы), так и кастомные при необходимости. Для обычного разработчика Spring это работает "за сценой", но понимание этого механизма важно для advanced scenarios и оптимизации.

Что такое HandlerAdapters? | PrepBro