스프링 MVC 구조와 핸들러 매핑, 핸들러 어댑터

jihan kong·2022년 8월 11일
0

Spring MVC

목록 보기
9/12
post-thumbnail

본 시리즈는 인프런 학습 사이트의 김영한 강사님의 java spring mvc - 백엔드 웹 개발 핵심 기술 편을 학습한 내용을 바탕으로 정리하였습니다.

지난 포스팅을 통해 FrontController 의 역할에 대해서 알게 되었다. SpringMVC에서도 FrontController 과 같이 공통처리 역할을 수행하는 컨트롤러가 존재한다. 이름은 디스패처 서블릿(Dispatcher Servlet) 이며, 이 디스패처 서블릿이 스프링 MVC의 핵심이다.

SpringMVC 전체 구조

🔁 요청 흐름

  1. 핸들러 조회 : 핸들러 매핑을 통해 요청 URL에 매핑된 핸들러(컨트롤러)를 조회한다.

  2. 핸들러 어댑터 조회 : 핸들러를 실행할 수 있는 핸들러 어댑터를 조회한다.

  3. 핸들러 어댑터 실행 : 핸들러 어댑터를 실행한다.

  4. 핸들러 실행 : 핸들러 어댑터가 실제 핸들러를 실행한다.

  5. ModelAndView 반환 : 핸들러 어댑터는 핸들러가 반환하는 정보를 ModelAndView로 변환해서 반환한다.

  6. viewResolver 호출 : 뷰 리졸버를 찾고 실행한다.
    ( JSP의 경우, InternalResourceViewResolver 가 자동 등록되고, 사용된다. )

  7. View 반환 : 뷰 리졸버는 뷰의 논리 이름을 물리 이름으로 바꾸고, 렌더링 역할을 담당하는 뷰 객체를 반환한다.
    ( JSP의 경우, InternalResourceView(JstlView) 를 반환하는데, 내부에 forward() 로직이 있다.)

  8. 뷰 렌더링 : 뷰를 통해서 뷰를 렌더링 한다.


요청 흐름은 위와 같다. 그러나 위의 내용만 봐서는 어떻게 동작하는지 감이 잘 오지 않는다. 하나씩 디테일하게 들어가보자.


HandlerMapping과 HandlerAdapter

스프링이 동작하는 첫 번째 관문은 핸들러 매핑 핸들러 어댑터 이다.

스프링 빈으로 등록된 어떠한 Controller 를 실행해야한다고 가정하자. 이 컨트롤러를 호출하려면 어떻게 해야할까?
일단 다음의 두 녀석이 열심히 열일(?)해야할 것이다.

HandlerMapping
핸들러 매핑을 통해 컨트롤러를 찾을 수 있어야 한다.
(일단 매핑이 되어야 스프링에서 실행할 수 있기 때문에)

HandlerAdapter
핸들러 매핑을 통해서 찾은 핸들러를 실행할 수 있는 핸들러 어댑터가 필요하다.


다행스럽게도 스프링은 이미 필요한 핸들러 매핑과 핸들러 어댑터를 대부분 구현해두었기 때문에 개발자가 직접 어댑터를 만드는 일은 거의 없다.
그렇다면 우리가 실제로 개발할때 혹은 실무에서 자주 사용하는 핸들러 매핑과 핸들러는 어떤게 있을까?

스프링 부트가 자동 등록하는 핸들러 매핑과 어댑터

HandlerMapping

0 순위 = RequestMappingHandlerMapping : 애노테이션 기반의 컨트롤러인 @RequestMapping에서 사용
1 순위 = BeanNameUrlHandlerMapping : 스프링 빈의 이름으로 핸들러를 찾는다.

HandlerAdapter

0 순위 = RequestMappingHandlerAdapter : 애노테이션 기반의 컨트롤러인 @RequestMapping에서 사용
1 순위 = HttpRequestHandlerAdapter : HttpRequestHandler 처리
2 순위 = SimpleControllerHandlerAdapter : Controller 인터페이스 처리 (애노테이션X, 과거에 사용)

HttpRequestHandler

핸들러 매핑과 어댑터를 더 잘 이해하기 위해 HttpRequestHandler 핸들러(컨트롤러)를 살펴보자.

HttpRequestHandler

public interface HttpRequestHandler {

	void handleRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException;
}

이를 다음과 같이 구현할 수 있다.

MyHttpRequestHandler

import org.springframework.stereotype.Component;
import org.springframework.web.HttpRequestHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.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");
		}
}

동작 순서

1. 핸들러 매핑으로 핸들러 조회

  • 위 상기된 순서대로 실행(0순위부터) 해서 핸들러를 찾게된다.
  • 이 경우 @Component("/springmvc/request-handler") 빈 이름으로 등록이 되었기 때문에 빈이름으로 핸들러를 찾게 해주는 BeanNameUrlHandlerMapping 가 실행에 성공

2. 핸들러 어댑터 조회

  • 위 상기된 순서대로 어댑터를 조회한다.
  • HttpRequestHandlerAdapterHttpRequestHandler 인터페이스를 지원하므로 대상이 된다.

정리하면, MyHttpRequestHandler 를 실행하면서 선택되어 사용된 객체는 다음과 같다.

  • HandlerMapping 은 BeanNameUrlHandlerMapping
  • HandlerAdapter 는 HttpRequestHandlerAdapter

@RequestMapping

예시에서는 BeanNameUrlHandlerMappingHttpRequestHandlerAdapter 를 사용했지만 위에서도 보았듯, 가장 우선순위가 높은 (0순위) 핸들러 매핑과 핸들러 어댑터는 각각 RequestMappingHandlerMapping, RequestMappingHandlerAdapter 이다.

@RequestMapping 의 앞 글자를 따서 만든 이름인데 이것이 바로 지금 스프링에서 주로 사용하는 애노테이션 기반의 컨트롤러를 지원하는 매핑과 어댑터이다. 실무에서는 99.9% 이 방식의 컨트롤러를 사용한다. 그만큼 중요한 컨트롤러이니 꼭 숙지하자!

profile
학습하며 도전하는 것을 즐기는 개발자

0개의 댓글