Spring

[Spring MVC] HandlerAdapter 가 존재하는 이유는 뭘까?

dragonwaterr 2025. 10. 3. 20:44

 

Spring MVC의 요청 처리 과정을 살펴보면, 흔히 이렇게 설명된다.

  1. 사용자의 요청이 들어오면 DispatcherServlet이 이를 가장 먼저 받는다. (Front Controller)
  2. HandlerMapping이 요청 URL에 맞는 핸들러를 찾아낸다.
  3. HandlerAdapter가 선택된 핸들러를 실행할 수 있는 준비를 한다. (핸들러 타입에 따라 실행 방법이 달라질 수 있음)
  4. 준비된 핸들러가 실제 컨트롤러 메서드로 호출된다.
  5. 컨트롤러 실행 결과는 ModelAndView 형태로 DispatcherServlet에 반환된다
  6. 이후 뷰 렌더링 단계(ViewResolver, View)로 넘어가 최종 응답을 사용자에게 돌려준다.

문득 이런 의문이 생겼다.

HandlerMapping에서 이미 컨트롤러를 찾았는데, 그냥 바로 실행하면 되지 않나?
굳이 HandlerAdapter를 거쳐가는 이유가 뭘까?

 

 

먼저 둘에 어떤 차이가 있는지 먼저 살펴봐야한다.


HandlerMapping  vs  HandlerAdapter

  • HandlerMapping
    단순히 “이 URL에 대한 핸들러는 누구인지”를 찾아내는 역할.
  • HandlerAdapter
    선택된 핸들러를 어떻게 실행할지 아는 존재.

즉, 무엇을 실행할지 찾는 것어떻게 실행할지 아는 것을 분리해둔 것이다.

 


그렇다면 왜 굳이 분리했을까?

핵심은 컨트롤러의 다양성에 있다.
스프링에서 컨트롤러는 한 가지 형태만 있는 게 아니다.

  • 예전에는 Controller 인터페이스를 구현하는 전통적인 방식이 있었고,
  • HttpRequestHandler처럼 서블릿 API와 유사하게 동작하는 컨트롤러도 있었으며,
  • 지금은 @Controller + @RequestMapping 기반의 어노테이션 방식이 사실상 표준이다.

만약 HandlerMapping이 단순히 컨트롤러를 찾는 것뿐만 아니라,
실행하는 방법까지 다 품고 있었다면 어땠을까?

  • 새로운 컨트롤러 타입이 등장할 때마다 HandlerMapping의 코드도 수정해야함.
  • 역할이 뒤섞여 복잡해지고, 확장성은 떨어짐.

HandlerAdapter가 가져오는 장점

  1. 확장성 (Open/Closed Principle)
    새로운 컨트롤러 형태가 필요하다면, 그에 맞는 HandlerAdapter 구현체만 추가하면 된다. 기존 DispatcherServlet이나 HandlerMapping은 전혀 수정할 필요가 없다.

  2. DispatcherServlet 단순화
    DispatcherServlet은 “핸들러를 찾고 → 어댑터를 통해 실행한다”는 흐름만 유지하면 된다.
    실행 세부사항은 Adapter에게 위임한다.

  3. 호출 방법의 다양성 수용
    어떤 컨트롤러는 service(req, res) 스타일로 직접 응답을 쓰기도 하고, 어떤 컨트롤러는 ModelAndView를 반환하기도 하며,
    어노테이션 기반 컨트롤러는 String, Object, ResponseEntity 등 훨씬 다양한 형태를 반환할 수 있다.
    Adapter는 이런 차이를 흡수해 DispatcherServlet이 일관된 흐름을 유지할 수 있게 해준다.

추가로 알게된 부분

HandlerAdapter의 우선순위를 지정할 수 있다 : Ordered와 HandlerAdapter의 우선순위

공식 문서와 코드를 보면, HandlerAdapter 구현체들은 Ordered 인터페이스(혹은 @Order 어노테이션)를 통해
우선순위를 가질 수 있다.

1. 반드시 구현해야 하는 건 아니다.
- Ordered를 구현하지 않으면 기본적으로 LOWEST_PRECEDENCE(= Integer.MAX_VALUE)로 간주된다.
(숫자가 낮을수록 우선순위가 높음)

2. DispatcherServlet의 역할은 단순하다.
- 모든 Adapter를 우선순위대로 정렬
- 순서대로 supports(handler) 메서드를 호출
- 해당 핸들러를 처리할 수 있는 첫 번째 Adapter를 선택

즉, DispatcherServlet만의 별도 기준은 없다. “줄세우기 + supports 검사”가 전부다.

 


마무리

정리하자면,

  • HandlerMapping은 “무엇을 실행할지”를 찾고,
  • HandlerAdapter는 “어떻게 실행할지”를 책임진다.

이 둘의 분리 덕분에 Spring MVC는 컨트롤러의 형태가 달라져도 유연하게 대응할 수 있다.
만약 HandlerAdapter가 없었다면, 새로운 컨트롤러 타입이 등장할 때마다
HandlerMapping이나 DispatcherServlet의 코드가 복잡해졌을 것이다.

 

즉, HandlerAdapter는 스프링 MVC가 다양한 컨트롤러 모델을 확장 가능하게 지원하기 위해 반드시 필요한 존재다.



 

다음 포스팅에서는, 내용을 이어서 HandlerAdapter의 구체적인 구현체들에는 어떤 것들이 있고, 각각 어떻게 다른지를 살펴볼 예정이다.