HandlerMapping, HandlerAdapter
핸들러 매핑과 핸들러 어댑터가 어떤 것들이 어떻게 사용되는지 알아보자. 지금은 전혀 사용하지 않지만, 과거에 주로 사용했던 스프링이 제공하는 간단한 컨트롤러로 핸들러 매핑과 어댑터를 이해해보자.
과거의 애노테이션을 사용하기 전에 스프링 컨트롤러를 보자.
org.springframework.web.servlet.mvc.Controller
public interface Controller {
ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws Exception;
}
과거의 컨트롤러이다. 참고로 현재 사용되는 @Controller와 완전히 다른 것이므로 헷갈리면 안된다.
한번 과거의 컨트롤러를 만들어보자.
@Component("/springmvc/old-controller")
public class OldController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response)
throws Exception {
System.out.println("OldController.handleRequest");
return null;
}
}
web으로 시작하는 Controller를 상속받아서 @Component를 통해 컨트롤러의 이름을 지어주고 실행해보면 콘솔창에 우리가 만든 문구가 보인다. 과거의 만들어진 이 컨트롤러는 어떻게 구현이 되어있을걸까.
해당 컨트롤러가 호출이 되려면 HandlerMapping과 HandlerAdapter가 필요하다.
스프링은 이미 필요한 핸들러 매핑과 핸들러 어댑터를 대부분 구현해두었다. 개발자가 직접 핸들러 매핑과 핸들러 어댑터를 만드는 일은 거의 없다.
스프링에서 제공해주는 핸들러매핑과 핸들러 어댑터 중에 몇가지만 확인해보자.
HandlerMapping
- 0순위 RequestMappingHandlerMapping : 애노테이션 기반의 컨트롤러인 @RequestMapping에서 사용
- 1순위 BeanNameUrlHandlerMapping : 스프링 빈의 이름으로 핸들러를 찾는다.
HandlerAdapter
- 0순위 RequestMappingHandlerAdapter : 애노테이션 기반의 컨트롤러인 @RequestMapping에서 사용
- 1순위 HttpRequestHandlerAdapter : HttpRequestHandler 처리
- 2순위 SimpleControllerHandlerAdapter : Controller 인터페이스(애노테이션X, 과거에 사용) 처리
제공해주는 핸들러매핑과 핸들러어댑터의 종류도 알아봤으니 하나씩 대입해보자.
- 핸들러 매핑으로 핸들러 조회
1. HandlerMapping 을 순서대로 실행해서, 핸들러를 찾는다.
2. 이 경우 빈 이름으로 핸들러를 찾아야 하기 때문에 이름 그대로 빈 이름으로 핸들러를 찾아주는 BeanNameUrlHandlerMapping 가 실행에 성공하고 핸들러인 OldController 를 반환한다. - 핸들러 어댑터 조회
1. HandlerAdapter 의 supports() 를 순서대로 호출한다.
2. SimpleControllerHandlerAdapter 가 Controller 인터페이스를 지원하므로 대상이 된다. - 핸들러 어댑터 실행
1. 디스패처 서블릿이 조회한 SimpleControllerHandlerAdapter 를 실행하면서 핸들러 정보도 함께 넘겨준다.
2. SimpleControllerHandlerAdapter 는 핸들러인 OldController 를 내부에서 실행하고, 그 결과를 반환한다
OldController 를 실행하면서 사용된 객체는 다음과 같다.
HandlerMapping = BeanNameUrlHandlerMapping
HandlerAdapter = SimpleControllerHandlerAdapter
이렇게 우리에게 필요한 핸들러매핑과 핸들러어댑터를 스프링에서 제공해주는 기능이 대신 해주면서 실행이 된다.
이번엔 다른 어댑터를 사용하는 예제를 보자.
이번에 사용할 어댑터는 HttpRequestHandlerAdapter이다.
public interface HttpRequestHandler {
void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException;
}
해당 어댑터가 처리하는 핸들러이다.
@Component("/springmvc/request-handler")
public class MyHttpRequestHandler implements HttpRequestHandler {
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("MyHttpRequestHandler.handleRequest");
}
}
해당 핸들러를 상속받은 다음예제를 보게 되면 핸들러 어댑터의 2순위에 걸리게 된다.
실행 순서
- 핸들러 매핑으로 핸들러 조회
1. HandlerMapping 을 순서대로 실행해서, 핸들러를 찾는다.
2. 이 경우 빈 이름으로 핸들러를 찾아야 하기 때문에 이름 그대로 빈 이름으로 핸들러를 찾아주는 BeanNameUrlHandlerMapping 가 실행에 성공하고 핸들러인 MyHttpRequestHandler 를 반환한다. - 핸들러 어댑터 조회
1. HandlerAdapter 의 supports() 를 순서대로 호출한다.
2. HttpRequestHandlerAdapter 가 HttpRequestHandler 인터페이스를 지원하므로 대상이 된다. - 핸들러 어댑터 실행
1. 디스패처 서블릿이 조회한 HttpRequestHandlerAdapter 를 실행하면서 핸들러 정보도 함께 넘겨준다.
2. HttpRequestHandlerAdapter 는 핸들러인 MyHttpRequestHandler 를 내부에서 실행하고, 그 결과를 반환한다
MyHttpRequestHandler 를 실행하면서 사용된 객체는 다음과 같다.
HandlerMapping = BeanNameUrlHandlerMapping
HandlerAdapter = HttpRequestHandlerAdapter
위의 두가지가 옛날 방식의 컨트롤러 처리 방식이라고 할 수 있다. 현재의 방식을 공부하기 위해 과거의 방식을 봤을 뿐이지 현재에선 99% @RequestMapping 방식을 사용한다. 이 방식은 엄청 많은 기능들이 있으며 전용 핸들러매핑과 핸들러어댑터가 존재한다. RequestMappingHandlerMapping , RequestMappingHandlerAdapter 이러듯 이 방식이 가장 최우선순위 이며 앞으로는 이방식으로 개발을 하면 된다.